]>
Commit | Line | Data |
---|---|---|
bcd61c0f SB |
1 | /* |
2 | * Copyright (c) 2013, The Linux Foundation. All rights reserved. | |
3 | * | |
4 | * This software is licensed under the terms of the GNU General Public | |
5 | * License version 2, as published by the Free Software Foundation, and | |
6 | * may be copied, distributed, and modified under those terms. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/bitops.h> | |
16 | #include <linux/err.h> | |
17 | #include <linux/bug.h> | |
18 | #include <linux/export.h> | |
19 | #include <linux/clk-provider.h> | |
20 | #include <linux/delay.h> | |
21 | #include <linux/regmap.h> | |
99cbd064 | 22 | #include <linux/math64.h> |
bcd61c0f SB |
23 | |
24 | #include <asm/div64.h> | |
25 | ||
26 | #include "clk-rcg.h" | |
50c6a503 | 27 | #include "common.h" |
bcd61c0f SB |
28 | |
29 | #define CMD_REG 0x0 | |
30 | #define CMD_UPDATE BIT(0) | |
31 | #define CMD_ROOT_EN BIT(1) | |
32 | #define CMD_DIRTY_CFG BIT(4) | |
33 | #define CMD_DIRTY_N BIT(5) | |
34 | #define CMD_DIRTY_M BIT(6) | |
35 | #define CMD_DIRTY_D BIT(7) | |
36 | #define CMD_ROOT_OFF BIT(31) | |
37 | ||
38 | #define CFG_REG 0x4 | |
39 | #define CFG_SRC_DIV_SHIFT 0 | |
40 | #define CFG_SRC_SEL_SHIFT 8 | |
41 | #define CFG_SRC_SEL_MASK (0x7 << CFG_SRC_SEL_SHIFT) | |
42 | #define CFG_MODE_SHIFT 12 | |
43 | #define CFG_MODE_MASK (0x3 << CFG_MODE_SHIFT) | |
44 | #define CFG_MODE_DUAL_EDGE (0x2 << CFG_MODE_SHIFT) | |
45 | ||
46 | #define M_REG 0x8 | |
47 | #define N_REG 0xc | |
48 | #define D_REG 0x10 | |
49 | ||
50 | static int clk_rcg2_is_enabled(struct clk_hw *hw) | |
51 | { | |
52 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
53 | u32 cmd; | |
54 | int ret; | |
55 | ||
56 | ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd); | |
57 | if (ret) | |
58 | return ret; | |
59 | ||
aa014149 | 60 | return (cmd & CMD_ROOT_OFF) == 0; |
bcd61c0f SB |
61 | } |
62 | ||
63 | static u8 clk_rcg2_get_parent(struct clk_hw *hw) | |
64 | { | |
65 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
66 | int num_parents = __clk_get_num_parents(hw->clk); | |
67 | u32 cfg; | |
68 | int i, ret; | |
69 | ||
70 | ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); | |
71 | if (ret) | |
72 | return ret; | |
73 | ||
74 | cfg &= CFG_SRC_SEL_MASK; | |
75 | cfg >>= CFG_SRC_SEL_SHIFT; | |
76 | ||
77 | for (i = 0; i < num_parents; i++) | |
78 | if (cfg == rcg->parent_map[i]) | |
79 | return i; | |
80 | ||
81 | return -EINVAL; | |
82 | } | |
83 | ||
84 | static int update_config(struct clk_rcg2 *rcg) | |
85 | { | |
86 | int count, ret; | |
87 | u32 cmd; | |
88 | struct clk_hw *hw = &rcg->clkr.hw; | |
89 | const char *name = __clk_get_name(hw->clk); | |
90 | ||
91 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, | |
92 | CMD_UPDATE, CMD_UPDATE); | |
93 | if (ret) | |
94 | return ret; | |
95 | ||
96 | /* Wait for update to take effect */ | |
97 | for (count = 500; count > 0; count--) { | |
98 | ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd); | |
99 | if (ret) | |
100 | return ret; | |
101 | if (!(cmd & CMD_UPDATE)) | |
102 | return 0; | |
103 | udelay(1); | |
104 | } | |
105 | ||
106 | WARN(1, "%s: rcg didn't update its configuration.", name); | |
107 | return 0; | |
108 | } | |
109 | ||
110 | static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index) | |
111 | { | |
112 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
113 | int ret; | |
114 | ||
115 | ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | |
116 | CFG_SRC_SEL_MASK, | |
117 | rcg->parent_map[index] << CFG_SRC_SEL_SHIFT); | |
118 | if (ret) | |
119 | return ret; | |
120 | ||
121 | return update_config(rcg); | |
122 | } | |
123 | ||
124 | /* | |
125 | * Calculate m/n:d rate | |
126 | * | |
127 | * parent_rate m | |
128 | * rate = ----------- x --- | |
129 | * hid_div n | |
130 | */ | |
131 | static unsigned long | |
132 | calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div) | |
133 | { | |
134 | if (hid_div) { | |
135 | rate *= 2; | |
136 | rate /= hid_div + 1; | |
137 | } | |
138 | ||
139 | if (mode) { | |
140 | u64 tmp = rate; | |
141 | tmp *= m; | |
142 | do_div(tmp, n); | |
143 | rate = tmp; | |
144 | } | |
145 | ||
146 | return rate; | |
147 | } | |
148 | ||
149 | static unsigned long | |
150 | clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |
151 | { | |
152 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
153 | u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask; | |
154 | ||
155 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); | |
156 | ||
157 | if (rcg->mnd_width) { | |
158 | mask = BIT(rcg->mnd_width) - 1; | |
159 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + M_REG, &m); | |
160 | m &= mask; | |
161 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + N_REG, &n); | |
162 | n = ~n; | |
163 | n &= mask; | |
164 | n += m; | |
165 | mode = cfg & CFG_MODE_MASK; | |
166 | mode >>= CFG_MODE_SHIFT; | |
167 | } | |
168 | ||
169 | mask = BIT(rcg->hid_width) - 1; | |
170 | hid_div = cfg >> CFG_SRC_DIV_SHIFT; | |
171 | hid_div &= mask; | |
172 | ||
173 | return calc_rate(parent_rate, m, n, mode, hid_div); | |
174 | } | |
175 | ||
bcd61c0f SB |
176 | static long _freq_tbl_determine_rate(struct clk_hw *hw, |
177 | const struct freq_tbl *f, unsigned long rate, | |
646cafc6 | 178 | unsigned long *p_rate, struct clk_hw **p_hw) |
bcd61c0f SB |
179 | { |
180 | unsigned long clk_flags; | |
646cafc6 | 181 | struct clk *p; |
bcd61c0f | 182 | |
50c6a503 | 183 | f = qcom_find_freq(f, rate); |
bcd61c0f SB |
184 | if (!f) |
185 | return -EINVAL; | |
186 | ||
187 | clk_flags = __clk_get_flags(hw->clk); | |
646cafc6 | 188 | p = clk_get_parent_by_index(hw->clk, f->src); |
bcd61c0f SB |
189 | if (clk_flags & CLK_SET_RATE_PARENT) { |
190 | if (f->pre_div) { | |
191 | rate /= 2; | |
192 | rate *= f->pre_div + 1; | |
193 | } | |
194 | ||
195 | if (f->n) { | |
196 | u64 tmp = rate; | |
197 | tmp = tmp * f->n; | |
198 | do_div(tmp, f->m); | |
199 | rate = tmp; | |
200 | } | |
201 | } else { | |
646cafc6 | 202 | rate = __clk_get_rate(p); |
bcd61c0f | 203 | } |
646cafc6 | 204 | *p_hw = __clk_get_hw(p); |
bcd61c0f SB |
205 | *p_rate = rate; |
206 | ||
207 | return f->freq; | |
208 | } | |
209 | ||
210 | static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate, | |
1c8e6004 | 211 | unsigned long min_rate, unsigned long max_rate, |
646cafc6 | 212 | unsigned long *p_rate, struct clk_hw **p) |
bcd61c0f SB |
213 | { |
214 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
215 | ||
216 | return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p); | |
217 | } | |
218 | ||
99cbd064 | 219 | static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f) |
bcd61c0f | 220 | { |
bcd61c0f SB |
221 | u32 cfg, mask; |
222 | int ret; | |
223 | ||
bcd61c0f SB |
224 | if (rcg->mnd_width && f->n) { |
225 | mask = BIT(rcg->mnd_width) - 1; | |
99cbd064 SB |
226 | ret = regmap_update_bits(rcg->clkr.regmap, |
227 | rcg->cmd_rcgr + M_REG, mask, f->m); | |
bcd61c0f SB |
228 | if (ret) |
229 | return ret; | |
230 | ||
99cbd064 SB |
231 | ret = regmap_update_bits(rcg->clkr.regmap, |
232 | rcg->cmd_rcgr + N_REG, mask, ~(f->n - f->m)); | |
bcd61c0f SB |
233 | if (ret) |
234 | return ret; | |
235 | ||
99cbd064 SB |
236 | ret = regmap_update_bits(rcg->clkr.regmap, |
237 | rcg->cmd_rcgr + D_REG, mask, ~f->n); | |
bcd61c0f SB |
238 | if (ret) |
239 | return ret; | |
240 | } | |
241 | ||
242 | mask = BIT(rcg->hid_width) - 1; | |
243 | mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK; | |
244 | cfg = f->pre_div << CFG_SRC_DIV_SHIFT; | |
245 | cfg |= rcg->parent_map[f->src] << CFG_SRC_SEL_SHIFT; | |
246 | if (rcg->mnd_width && f->n) | |
247 | cfg |= CFG_MODE_DUAL_EDGE; | |
99cbd064 SB |
248 | ret = regmap_update_bits(rcg->clkr.regmap, |
249 | rcg->cmd_rcgr + CFG_REG, mask, cfg); | |
bcd61c0f SB |
250 | if (ret) |
251 | return ret; | |
252 | ||
253 | return update_config(rcg); | |
254 | } | |
255 | ||
99cbd064 SB |
256 | static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate) |
257 | { | |
258 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
259 | const struct freq_tbl *f; | |
260 | ||
50c6a503 | 261 | f = qcom_find_freq(rcg->freq_tbl, rate); |
99cbd064 SB |
262 | if (!f) |
263 | return -EINVAL; | |
264 | ||
265 | return clk_rcg2_configure(rcg, f); | |
266 | } | |
267 | ||
bcd61c0f SB |
268 | static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate, |
269 | unsigned long parent_rate) | |
270 | { | |
271 | return __clk_rcg2_set_rate(hw, rate); | |
272 | } | |
273 | ||
274 | static int clk_rcg2_set_rate_and_parent(struct clk_hw *hw, | |
275 | unsigned long rate, unsigned long parent_rate, u8 index) | |
276 | { | |
277 | return __clk_rcg2_set_rate(hw, rate); | |
278 | } | |
279 | ||
280 | const struct clk_ops clk_rcg2_ops = { | |
281 | .is_enabled = clk_rcg2_is_enabled, | |
282 | .get_parent = clk_rcg2_get_parent, | |
283 | .set_parent = clk_rcg2_set_parent, | |
284 | .recalc_rate = clk_rcg2_recalc_rate, | |
285 | .determine_rate = clk_rcg2_determine_rate, | |
286 | .set_rate = clk_rcg2_set_rate, | |
287 | .set_rate_and_parent = clk_rcg2_set_rate_and_parent, | |
288 | }; | |
289 | EXPORT_SYMBOL_GPL(clk_rcg2_ops); | |
99cbd064 SB |
290 | |
291 | struct frac_entry { | |
292 | int num; | |
293 | int den; | |
294 | }; | |
295 | ||
296 | static const struct frac_entry frac_table_675m[] = { /* link rate of 270M */ | |
297 | { 52, 295 }, /* 119 M */ | |
298 | { 11, 57 }, /* 130.25 M */ | |
299 | { 63, 307 }, /* 138.50 M */ | |
300 | { 11, 50 }, /* 148.50 M */ | |
301 | { 47, 206 }, /* 154 M */ | |
302 | { 31, 100 }, /* 205.25 M */ | |
303 | { 107, 269 }, /* 268.50 M */ | |
304 | { }, | |
305 | }; | |
306 | ||
307 | static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */ | |
308 | { 31, 211 }, /* 119 M */ | |
309 | { 32, 199 }, /* 130.25 M */ | |
310 | { 63, 307 }, /* 138.50 M */ | |
311 | { 11, 60 }, /* 148.50 M */ | |
312 | { 50, 263 }, /* 154 M */ | |
313 | { 31, 120 }, /* 205.25 M */ | |
314 | { 119, 359 }, /* 268.50 M */ | |
315 | { }, | |
316 | }; | |
317 | ||
318 | static int clk_edp_pixel_set_rate(struct clk_hw *hw, unsigned long rate, | |
319 | unsigned long parent_rate) | |
320 | { | |
321 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
322 | struct freq_tbl f = *rcg->freq_tbl; | |
323 | const struct frac_entry *frac; | |
324 | int delta = 100000; | |
325 | s64 src_rate = parent_rate; | |
326 | s64 request; | |
327 | u32 mask = BIT(rcg->hid_width) - 1; | |
328 | u32 hid_div; | |
329 | ||
330 | if (src_rate == 810000000) | |
331 | frac = frac_table_810m; | |
332 | else | |
333 | frac = frac_table_675m; | |
334 | ||
335 | for (; frac->num; frac++) { | |
336 | request = rate; | |
337 | request *= frac->den; | |
338 | request = div_s64(request, frac->num); | |
339 | if ((src_rate < (request - delta)) || | |
340 | (src_rate > (request + delta))) | |
341 | continue; | |
342 | ||
343 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | |
344 | &hid_div); | |
345 | f.pre_div = hid_div; | |
346 | f.pre_div >>= CFG_SRC_DIV_SHIFT; | |
347 | f.pre_div &= mask; | |
348 | f.m = frac->num; | |
349 | f.n = frac->den; | |
350 | ||
351 | return clk_rcg2_configure(rcg, &f); | |
352 | } | |
353 | ||
354 | return -EINVAL; | |
355 | } | |
356 | ||
357 | static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw, | |
358 | unsigned long rate, unsigned long parent_rate, u8 index) | |
359 | { | |
360 | /* Parent index is set statically in frequency table */ | |
361 | return clk_edp_pixel_set_rate(hw, rate, parent_rate); | |
362 | } | |
363 | ||
364 | static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, | |
1c8e6004 TV |
365 | unsigned long min_rate, |
366 | unsigned long max_rate, | |
646cafc6 | 367 | unsigned long *p_rate, struct clk_hw **p) |
99cbd064 SB |
368 | { |
369 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
370 | const struct freq_tbl *f = rcg->freq_tbl; | |
371 | const struct frac_entry *frac; | |
372 | int delta = 100000; | |
373 | s64 src_rate = *p_rate; | |
374 | s64 request; | |
375 | u32 mask = BIT(rcg->hid_width) - 1; | |
376 | u32 hid_div; | |
377 | ||
378 | /* Force the correct parent */ | |
646cafc6 | 379 | *p = __clk_get_hw(clk_get_parent_by_index(hw->clk, f->src)); |
99cbd064 SB |
380 | |
381 | if (src_rate == 810000000) | |
382 | frac = frac_table_810m; | |
383 | else | |
384 | frac = frac_table_675m; | |
385 | ||
386 | for (; frac->num; frac++) { | |
387 | request = rate; | |
388 | request *= frac->den; | |
389 | request = div_s64(request, frac->num); | |
390 | if ((src_rate < (request - delta)) || | |
391 | (src_rate > (request + delta))) | |
392 | continue; | |
393 | ||
394 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | |
395 | &hid_div); | |
396 | hid_div >>= CFG_SRC_DIV_SHIFT; | |
397 | hid_div &= mask; | |
398 | ||
399 | return calc_rate(src_rate, frac->num, frac->den, !!frac->den, | |
400 | hid_div); | |
401 | } | |
402 | ||
403 | return -EINVAL; | |
404 | } | |
405 | ||
406 | const struct clk_ops clk_edp_pixel_ops = { | |
407 | .is_enabled = clk_rcg2_is_enabled, | |
408 | .get_parent = clk_rcg2_get_parent, | |
409 | .set_parent = clk_rcg2_set_parent, | |
410 | .recalc_rate = clk_rcg2_recalc_rate, | |
411 | .set_rate = clk_edp_pixel_set_rate, | |
412 | .set_rate_and_parent = clk_edp_pixel_set_rate_and_parent, | |
413 | .determine_rate = clk_edp_pixel_determine_rate, | |
414 | }; | |
415 | EXPORT_SYMBOL_GPL(clk_edp_pixel_ops); | |
416 | ||
417 | static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate, | |
1c8e6004 | 418 | unsigned long min_rate, unsigned long max_rate, |
646cafc6 | 419 | unsigned long *p_rate, struct clk_hw **p_hw) |
99cbd064 SB |
420 | { |
421 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
422 | const struct freq_tbl *f = rcg->freq_tbl; | |
423 | unsigned long parent_rate, div; | |
424 | u32 mask = BIT(rcg->hid_width) - 1; | |
646cafc6 | 425 | struct clk *p; |
99cbd064 SB |
426 | |
427 | if (rate == 0) | |
428 | return -EINVAL; | |
429 | ||
646cafc6 TV |
430 | p = clk_get_parent_by_index(hw->clk, f->src); |
431 | *p_hw = __clk_get_hw(p); | |
432 | *p_rate = parent_rate = __clk_round_rate(p, rate); | |
99cbd064 SB |
433 | |
434 | div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; | |
435 | div = min_t(u32, div, mask); | |
436 | ||
437 | return calc_rate(parent_rate, 0, 0, 0, div); | |
438 | } | |
439 | ||
440 | static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate, | |
441 | unsigned long parent_rate) | |
442 | { | |
443 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
444 | struct freq_tbl f = *rcg->freq_tbl; | |
445 | unsigned long div; | |
446 | u32 mask = BIT(rcg->hid_width) - 1; | |
447 | ||
448 | div = DIV_ROUND_UP((2 * parent_rate), rate) - 1; | |
449 | div = min_t(u32, div, mask); | |
450 | ||
451 | f.pre_div = div; | |
452 | ||
453 | return clk_rcg2_configure(rcg, &f); | |
454 | } | |
455 | ||
456 | static int clk_byte_set_rate_and_parent(struct clk_hw *hw, | |
457 | unsigned long rate, unsigned long parent_rate, u8 index) | |
458 | { | |
459 | /* Parent index is set statically in frequency table */ | |
460 | return clk_byte_set_rate(hw, rate, parent_rate); | |
461 | } | |
462 | ||
463 | const struct clk_ops clk_byte_ops = { | |
464 | .is_enabled = clk_rcg2_is_enabled, | |
465 | .get_parent = clk_rcg2_get_parent, | |
466 | .set_parent = clk_rcg2_set_parent, | |
467 | .recalc_rate = clk_rcg2_recalc_rate, | |
468 | .set_rate = clk_byte_set_rate, | |
469 | .set_rate_and_parent = clk_byte_set_rate_and_parent, | |
470 | .determine_rate = clk_byte_determine_rate, | |
471 | }; | |
472 | EXPORT_SYMBOL_GPL(clk_byte_ops); | |
473 | ||
474 | static const struct frac_entry frac_table_pixel[] = { | |
475 | { 3, 8 }, | |
476 | { 2, 9 }, | |
477 | { 4, 9 }, | |
478 | { 1, 1 }, | |
479 | { } | |
480 | }; | |
481 | ||
482 | static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate, | |
1c8e6004 TV |
483 | unsigned long min_rate, |
484 | unsigned long max_rate, | |
646cafc6 | 485 | unsigned long *p_rate, struct clk_hw **p) |
99cbd064 SB |
486 | { |
487 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
488 | unsigned long request, src_rate; | |
489 | int delta = 100000; | |
490 | const struct freq_tbl *f = rcg->freq_tbl; | |
491 | const struct frac_entry *frac = frac_table_pixel; | |
646cafc6 TV |
492 | struct clk *parent = clk_get_parent_by_index(hw->clk, f->src); |
493 | ||
494 | *p = __clk_get_hw(parent); | |
99cbd064 SB |
495 | |
496 | for (; frac->num; frac++) { | |
497 | request = (rate * frac->den) / frac->num; | |
498 | ||
499 | src_rate = __clk_round_rate(parent, request); | |
500 | if ((src_rate < (request - delta)) || | |
501 | (src_rate > (request + delta))) | |
502 | continue; | |
503 | ||
504 | *p_rate = src_rate; | |
505 | return (src_rate * frac->num) / frac->den; | |
506 | } | |
507 | ||
508 | return -EINVAL; | |
509 | } | |
510 | ||
511 | static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate, | |
512 | unsigned long parent_rate) | |
513 | { | |
514 | struct clk_rcg2 *rcg = to_clk_rcg2(hw); | |
515 | struct freq_tbl f = *rcg->freq_tbl; | |
516 | const struct frac_entry *frac = frac_table_pixel; | |
517 | unsigned long request, src_rate; | |
518 | int delta = 100000; | |
519 | u32 mask = BIT(rcg->hid_width) - 1; | |
520 | u32 hid_div; | |
521 | struct clk *parent = clk_get_parent_by_index(hw->clk, f.src); | |
522 | ||
523 | for (; frac->num; frac++) { | |
524 | request = (rate * frac->den) / frac->num; | |
525 | ||
526 | src_rate = __clk_round_rate(parent, request); | |
527 | if ((src_rate < (request - delta)) || | |
528 | (src_rate > (request + delta))) | |
529 | continue; | |
530 | ||
531 | regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, | |
532 | &hid_div); | |
533 | f.pre_div = hid_div; | |
534 | f.pre_div >>= CFG_SRC_DIV_SHIFT; | |
535 | f.pre_div &= mask; | |
536 | f.m = frac->num; | |
537 | f.n = frac->den; | |
538 | ||
539 | return clk_rcg2_configure(rcg, &f); | |
540 | } | |
541 | return -EINVAL; | |
542 | } | |
543 | ||
544 | static int clk_pixel_set_rate_and_parent(struct clk_hw *hw, unsigned long rate, | |
545 | unsigned long parent_rate, u8 index) | |
546 | { | |
547 | /* Parent index is set statically in frequency table */ | |
548 | return clk_pixel_set_rate(hw, rate, parent_rate); | |
549 | } | |
550 | ||
551 | const struct clk_ops clk_pixel_ops = { | |
552 | .is_enabled = clk_rcg2_is_enabled, | |
553 | .get_parent = clk_rcg2_get_parent, | |
554 | .set_parent = clk_rcg2_set_parent, | |
555 | .recalc_rate = clk_rcg2_recalc_rate, | |
556 | .set_rate = clk_pixel_set_rate, | |
557 | .set_rate_and_parent = clk_pixel_set_rate_and_parent, | |
558 | .determine_rate = clk_pixel_determine_rate, | |
559 | }; | |
560 | EXPORT_SYMBOL_GPL(clk_pixel_ops); |