blob: e4c36dfdc85145fd3530c65fdc07d9df6920a1aa [file] [log] [blame]
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001/*
2 * Driver for IDT Versaclock 5
3 *
4 * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17/*
18 * Possible optimizations:
19 * - Use spread spectrum
20 * - Use integer divider in FOD if applicable
21 */
22
23#include <linux/clk.h>
24#include <linux/clk-provider.h>
25#include <linux/delay.h>
26#include <linux/i2c.h>
27#include <linux/interrupt.h>
28#include <linux/mod_devicetable.h>
29#include <linux/module.h>
30#include <linux/of.h>
31#include <linux/of_platform.h>
32#include <linux/rational.h>
33#include <linux/regmap.h>
34#include <linux/slab.h>
35
36/* VersaClock5 registers */
37#define VC5_OTP_CONTROL 0x00
38
39/* Factory-reserved register block */
40#define VC5_RSVD_DEVICE_ID 0x01
41#define VC5_RSVD_ADC_GAIN_7_0 0x02
42#define VC5_RSVD_ADC_GAIN_15_8 0x03
43#define VC5_RSVD_ADC_OFFSET_7_0 0x04
44#define VC5_RSVD_ADC_OFFSET_15_8 0x05
45#define VC5_RSVD_TEMPY 0x06
46#define VC5_RSVD_OFFSET_TBIN 0x07
47#define VC5_RSVD_GAIN 0x08
48#define VC5_RSVD_TEST_NP 0x09
49#define VC5_RSVD_UNUSED 0x0a
50#define VC5_RSVD_BANDGAP_TRIM_UP 0x0b
51#define VC5_RSVD_BANDGAP_TRIM_DN 0x0c
52#define VC5_RSVD_CLK_R_12_CLK_AMP_4 0x0d
53#define VC5_RSVD_CLK_R_34_CLK_AMP_4 0x0e
54#define VC5_RSVD_CLK_AMP_123 0x0f
55
56/* Configuration register block */
57#define VC5_PRIM_SRC_SHDN 0x10
58#define VC5_PRIM_SRC_SHDN_EN_XTAL BIT(7)
59#define VC5_PRIM_SRC_SHDN_EN_CLKIN BIT(6)
Marek Vasut8c1ebe92017-07-09 15:28:12 +020060#define VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ BIT(3)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +010061#define VC5_PRIM_SRC_SHDN_SP BIT(1)
62#define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN BIT(0)
63
64#define VC5_VCO_BAND 0x11
65#define VC5_XTAL_X1_LOAD_CAP 0x12
66#define VC5_XTAL_X2_LOAD_CAP 0x13
67#define VC5_REF_DIVIDER 0x15
68#define VC5_REF_DIVIDER_SEL_PREDIV2 BIT(7)
69#define VC5_REF_DIVIDER_REF_DIV(n) ((n) & 0x3f)
70
71#define VC5_VCO_CTRL_AND_PREDIV 0x16
72#define VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV BIT(7)
73
74#define VC5_FEEDBACK_INT_DIV 0x17
75#define VC5_FEEDBACK_INT_DIV_BITS 0x18
76#define VC5_FEEDBACK_FRAC_DIV(n) (0x19 + (n))
77#define VC5_RC_CONTROL0 0x1e
78#define VC5_RC_CONTROL1 0x1f
79/* Register 0x20 is factory reserved */
80
81/* Output divider control for divider 1,2,3,4 */
82#define VC5_OUT_DIV_CONTROL(idx) (0x21 + ((idx) * 0x10))
83#define VC5_OUT_DIV_CONTROL_RESET BIT(7)
84#define VC5_OUT_DIV_CONTROL_SELB_NORM BIT(3)
85#define VC5_OUT_DIV_CONTROL_SEL_EXT BIT(2)
86#define VC5_OUT_DIV_CONTROL_INT_MODE BIT(1)
87#define VC5_OUT_DIV_CONTROL_EN_FOD BIT(0)
88
89#define VC5_OUT_DIV_FRAC(idx, n) (0x22 + ((idx) * 0x10) + (n))
90#define VC5_OUT_DIV_FRAC4_OD_SCEE BIT(1)
91
92#define VC5_OUT_DIV_STEP_SPREAD(idx, n) (0x26 + ((idx) * 0x10) + (n))
93#define VC5_OUT_DIV_SPREAD_MOD(idx, n) (0x29 + ((idx) * 0x10) + (n))
94#define VC5_OUT_DIV_SKEW_INT(idx, n) (0x2b + ((idx) * 0x10) + (n))
95#define VC5_OUT_DIV_INT(idx, n) (0x2d + ((idx) * 0x10) + (n))
96#define VC5_OUT_DIV_SKEW_FRAC(idx) (0x2f + ((idx) * 0x10))
97/* Registers 0x30, 0x40, 0x50 are factory reserved */
98
99/* Clock control register for clock 1,2 */
100#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
101#define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0)
102
103#define VC5_CLK_OE_SHDN 0x68
104#define VC5_CLK_OS_SHDN 0x69
105
106#define VC5_GLOBAL_REGISTER 0x76
107#define VC5_GLOBAL_REGISTER_GLOBAL_RESET BIT(5)
108
109/* PLL/VCO runs between 2.5 GHz and 3.0 GHz */
110#define VC5_PLL_VCO_MIN 2500000000UL
111#define VC5_PLL_VCO_MAX 3000000000UL
112
113/* VC5 Input mux settings */
114#define VC5_MUX_IN_XIN BIT(0)
115#define VC5_MUX_IN_CLKIN BIT(1)
116
Alexey Firago9adddb02017-04-07 12:12:22 +0300117/* Maximum number of clk_out supported by this driver */
Alexey Firago1193e142017-04-07 12:12:24 +0300118#define VC5_MAX_CLK_OUT_NUM 5
Alexey Firago9adddb02017-04-07 12:12:22 +0300119
120/* Maximum number of FODs supported by this driver */
Alexey Firago1193e142017-04-07 12:12:24 +0300121#define VC5_MAX_FOD_NUM 4
Alexey Firago9adddb02017-04-07 12:12:22 +0300122
123/* flags to describe chip features */
124/* chip has built-in oscilator */
125#define VC5_HAS_INTERNAL_XTAL BIT(0)
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200126/* chip has PFD requency doubler */
127#define VC5_HAS_PFD_FREQ_DBL BIT(1)
Alexey Firago9adddb02017-04-07 12:12:22 +0300128
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100129/* Supported IDT VC5 models. */
130enum vc5_model {
131 IDT_VC5_5P49V5923,
132 IDT_VC5_5P49V5933,
Alexey Firago1193e142017-04-07 12:12:24 +0300133 IDT_VC5_5P49V5935,
Marek Vasutdbf6b162017-07-09 15:28:14 +0200134 IDT_VC6_5P49V6901,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100135};
136
Alexey Firago9adddb02017-04-07 12:12:22 +0300137/* Structure to describe features of a particular VC5 model */
138struct vc5_chip_info {
139 const enum vc5_model model;
140 const unsigned int clk_fod_cnt;
141 const unsigned int clk_out_cnt;
142 const u32 flags;
143};
144
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100145struct vc5_driver_data;
146
147struct vc5_hw_data {
148 struct clk_hw hw;
149 struct vc5_driver_data *vc5;
150 u32 div_int;
151 u32 div_frc;
152 unsigned int num;
153};
154
155struct vc5_driver_data {
156 struct i2c_client *client;
157 struct regmap *regmap;
Alexey Firago9adddb02017-04-07 12:12:22 +0300158 const struct vc5_chip_info *chip_info;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100159
160 struct clk *pin_xin;
161 struct clk *pin_clkin;
162 unsigned char clk_mux_ins;
163 struct clk_hw clk_mux;
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200164 struct clk_hw clk_mul;
Marek Vasut55997db2017-07-09 15:28:11 +0200165 struct clk_hw clk_pfd;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100166 struct vc5_hw_data clk_pll;
Alexey Firago9adddb02017-04-07 12:12:22 +0300167 struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
168 struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100169};
170
171static const char * const vc5_mux_names[] = {
172 "mux"
173};
174
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200175static const char * const vc5_dbl_names[] = {
176 "dbl"
177};
178
Marek Vasut55997db2017-07-09 15:28:11 +0200179static const char * const vc5_pfd_names[] = {
180 "pfd"
181};
182
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100183static const char * const vc5_pll_names[] = {
184 "pll"
185};
186
187static const char * const vc5_fod_names[] = {
188 "fod0", "fod1", "fod2", "fod3",
189};
190
191static const char * const vc5_clk_out_names[] = {
192 "out0_sel_i2cb", "out1", "out2", "out3", "out4",
193};
194
195/*
196 * VersaClock5 i2c regmap
197 */
198static bool vc5_regmap_is_writeable(struct device *dev, unsigned int reg)
199{
200 /* Factory reserved regs, make them read-only */
201 if (reg <= 0xf)
202 return false;
203
204 /* Factory reserved regs, make them read-only */
205 if (reg == 0x14 || reg == 0x1c || reg == 0x1d)
206 return false;
207
208 return true;
209}
210
211static const struct regmap_config vc5_regmap_config = {
212 .reg_bits = 8,
213 .val_bits = 8,
214 .cache_type = REGCACHE_RBTREE,
215 .max_register = 0x76,
216 .writeable_reg = vc5_regmap_is_writeable,
217};
218
219/*
220 * VersaClock5 input multiplexer between XTAL and CLKIN divider
221 */
222static unsigned char vc5_mux_get_parent(struct clk_hw *hw)
223{
224 struct vc5_driver_data *vc5 =
225 container_of(hw, struct vc5_driver_data, clk_mux);
226 const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
227 unsigned int src;
228
229 regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src);
230 src &= mask;
231
232 if (src == VC5_PRIM_SRC_SHDN_EN_XTAL)
233 return 0;
234
235 if (src == VC5_PRIM_SRC_SHDN_EN_CLKIN)
236 return 1;
237
238 dev_warn(&vc5->client->dev,
239 "Invalid clock input configuration (%02x)\n", src);
240 return 0;
241}
242
243static int vc5_mux_set_parent(struct clk_hw *hw, u8 index)
244{
245 struct vc5_driver_data *vc5 =
246 container_of(hw, struct vc5_driver_data, clk_mux);
247 const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
248 u8 src;
249
250 if ((index > 1) || !vc5->clk_mux_ins)
251 return -EINVAL;
252
253 if (vc5->clk_mux_ins == (VC5_MUX_IN_CLKIN | VC5_MUX_IN_XIN)) {
254 if (index == 0)
255 src = VC5_PRIM_SRC_SHDN_EN_XTAL;
256 if (index == 1)
257 src = VC5_PRIM_SRC_SHDN_EN_CLKIN;
258 } else {
259 if (index != 0)
260 return -EINVAL;
261
262 if (vc5->clk_mux_ins == VC5_MUX_IN_XIN)
263 src = VC5_PRIM_SRC_SHDN_EN_XTAL;
264 if (vc5->clk_mux_ins == VC5_MUX_IN_CLKIN)
265 src = VC5_PRIM_SRC_SHDN_EN_CLKIN;
266 }
267
268 return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src);
269}
270
Marek Vasut55997db2017-07-09 15:28:11 +0200271static const struct clk_ops vc5_mux_ops = {
272 .set_parent = vc5_mux_set_parent,
273 .get_parent = vc5_mux_get_parent,
274};
275
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200276static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
277 unsigned long parent_rate)
278{
279 struct vc5_driver_data *vc5 =
280 container_of(hw, struct vc5_driver_data, clk_mul);
281 unsigned int premul;
282
283 regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
284 if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ)
285 parent_rate *= 2;
286
287 return parent_rate;
288}
289
290static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate,
291 unsigned long *parent_rate)
292{
293 if ((*parent_rate == rate) || ((*parent_rate * 2) == rate))
294 return rate;
295 else
296 return -EINVAL;
297}
298
299static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
300 unsigned long parent_rate)
301{
302 struct vc5_driver_data *vc5 =
303 container_of(hw, struct vc5_driver_data, clk_mul);
304 u32 mask;
305
306 if ((parent_rate * 2) == rate)
307 mask = VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ;
308 else
309 mask = 0;
310
311 regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
312 VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
313 mask);
314
315 return 0;
316}
317
318static const struct clk_ops vc5_dbl_ops = {
319 .recalc_rate = vc5_dbl_recalc_rate,
320 .round_rate = vc5_dbl_round_rate,
321 .set_rate = vc5_dbl_set_rate,
322};
323
Marek Vasut55997db2017-07-09 15:28:11 +0200324static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100325 unsigned long parent_rate)
326{
327 struct vc5_driver_data *vc5 =
Marek Vasut55997db2017-07-09 15:28:11 +0200328 container_of(hw, struct vc5_driver_data, clk_pfd);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100329 unsigned int prediv, div;
330
331 regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
332
333 /* The bypass_prediv is set, PLL fed from Ref_in directly. */
334 if (prediv & VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV)
335 return parent_rate;
336
337 regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div);
338
339 /* The Sel_prediv2 is set, PLL fed from prediv2 (Ref_in / 2) */
340 if (div & VC5_REF_DIVIDER_SEL_PREDIV2)
341 return parent_rate / 2;
342 else
343 return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
344}
345
Marek Vasut55997db2017-07-09 15:28:11 +0200346static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100347 unsigned long *parent_rate)
348{
349 unsigned long idiv;
350
351 /* PLL cannot operate with input clock above 50 MHz. */
352 if (rate > 50000000)
353 return -EINVAL;
354
355 /* CLKIN within range of PLL input, feed directly to PLL. */
356 if (*parent_rate <= 50000000)
357 return *parent_rate;
358
359 idiv = DIV_ROUND_UP(*parent_rate, rate);
360 if (idiv > 127)
361 return -EINVAL;
362
363 return *parent_rate / idiv;
364}
365
Marek Vasut55997db2017-07-09 15:28:11 +0200366static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100367 unsigned long parent_rate)
368{
369 struct vc5_driver_data *vc5 =
Marek Vasut55997db2017-07-09 15:28:11 +0200370 container_of(hw, struct vc5_driver_data, clk_pfd);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100371 unsigned long idiv;
372 u8 div;
373
374 /* CLKIN within range of PLL input, feed directly to PLL. */
375 if (parent_rate <= 50000000) {
376 regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
377 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV,
378 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
379 regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00);
380 return 0;
381 }
382
383 idiv = DIV_ROUND_UP(parent_rate, rate);
384
385 /* We have dedicated div-2 predivider. */
386 if (idiv == 2)
387 div = VC5_REF_DIVIDER_SEL_PREDIV2;
388 else
389 div = VC5_REF_DIVIDER_REF_DIV(idiv);
390
391 regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div);
392 regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
393 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, 0);
394
395 return 0;
396}
397
Marek Vasut55997db2017-07-09 15:28:11 +0200398static const struct clk_ops vc5_pfd_ops = {
399 .recalc_rate = vc5_pfd_recalc_rate,
400 .round_rate = vc5_pfd_round_rate,
401 .set_rate = vc5_pfd_set_rate,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100402};
403
404/*
405 * VersaClock5 PLL/VCO
406 */
407static unsigned long vc5_pll_recalc_rate(struct clk_hw *hw,
408 unsigned long parent_rate)
409{
410 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
411 struct vc5_driver_data *vc5 = hwdata->vc5;
412 u32 div_int, div_frc;
413 u8 fb[5];
414
415 regmap_bulk_read(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5);
416
417 div_int = (fb[0] << 4) | (fb[1] >> 4);
418 div_frc = (fb[2] << 16) | (fb[3] << 8) | fb[4];
419
420 /* The PLL divider has 12 integer bits and 24 fractional bits */
421 return (parent_rate * div_int) + ((parent_rate * div_frc) >> 24);
422}
423
424static long vc5_pll_round_rate(struct clk_hw *hw, unsigned long rate,
425 unsigned long *parent_rate)
426{
427 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
428 u32 div_int;
429 u64 div_frc;
430
431 if (rate < VC5_PLL_VCO_MIN)
432 rate = VC5_PLL_VCO_MIN;
433 if (rate > VC5_PLL_VCO_MAX)
434 rate = VC5_PLL_VCO_MAX;
435
436 /* Determine integer part, which is 12 bit wide */
437 div_int = rate / *parent_rate;
438 if (div_int > 0xfff)
439 rate = *parent_rate * 0xfff;
440
441 /* Determine best fractional part, which is 24 bit wide */
442 div_frc = rate % *parent_rate;
443 div_frc *= BIT(24) - 1;
444 do_div(div_frc, *parent_rate);
445
446 hwdata->div_int = div_int;
447 hwdata->div_frc = (u32)div_frc;
448
449 return (*parent_rate * div_int) + ((*parent_rate * div_frc) >> 24);
450}
451
452static int vc5_pll_set_rate(struct clk_hw *hw, unsigned long rate,
453 unsigned long parent_rate)
454{
455 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
456 struct vc5_driver_data *vc5 = hwdata->vc5;
457 u8 fb[5];
458
459 fb[0] = hwdata->div_int >> 4;
460 fb[1] = hwdata->div_int << 4;
461 fb[2] = hwdata->div_frc >> 16;
462 fb[3] = hwdata->div_frc >> 8;
463 fb[4] = hwdata->div_frc;
464
465 return regmap_bulk_write(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5);
466}
467
468static const struct clk_ops vc5_pll_ops = {
469 .recalc_rate = vc5_pll_recalc_rate,
470 .round_rate = vc5_pll_round_rate,
471 .set_rate = vc5_pll_set_rate,
472};
473
474static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw,
475 unsigned long parent_rate)
476{
477 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
478 struct vc5_driver_data *vc5 = hwdata->vc5;
479 /* VCO frequency is divided by two before entering FOD */
480 u32 f_in = parent_rate / 2;
481 u32 div_int, div_frc;
482 u8 od_int[2];
483 u8 od_frc[4];
484
485 regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_INT(hwdata->num, 0),
486 od_int, 2);
487 regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
488 od_frc, 4);
489
490 div_int = (od_int[0] << 4) | (od_int[1] >> 4);
491 div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) |
492 (od_frc[2] << 6) | (od_frc[3] >> 2);
493
Marek Vasut3bded562017-07-09 15:28:07 +0200494 /* Avoid division by zero if the output is not configured. */
495 if (div_int == 0 && div_frc == 0)
496 return 0;
497
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100498 /* The PLL divider has 12 integer bits and 30 fractional bits */
499 return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
500}
501
502static long vc5_fod_round_rate(struct clk_hw *hw, unsigned long rate,
503 unsigned long *parent_rate)
504{
505 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
506 /* VCO frequency is divided by two before entering FOD */
507 u32 f_in = *parent_rate / 2;
508 u32 div_int;
509 u64 div_frc;
510
511 /* Determine integer part, which is 12 bit wide */
512 div_int = f_in / rate;
513 /*
514 * WARNING: The clock chip does not output signal if the integer part
515 * of the divider is 0xfff and fractional part is non-zero.
516 * Clamp the divider at 0xffe to keep the code simple.
517 */
518 if (div_int > 0xffe) {
519 div_int = 0xffe;
520 rate = f_in / div_int;
521 }
522
523 /* Determine best fractional part, which is 30 bit wide */
524 div_frc = f_in % rate;
525 div_frc <<= 24;
526 do_div(div_frc, rate);
527
528 hwdata->div_int = div_int;
529 hwdata->div_frc = (u32)div_frc;
530
531 return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
532}
533
534static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate,
535 unsigned long parent_rate)
536{
537 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
538 struct vc5_driver_data *vc5 = hwdata->vc5;
539 u8 data[14] = {
540 hwdata->div_frc >> 22, hwdata->div_frc >> 14,
541 hwdata->div_frc >> 6, hwdata->div_frc << 2,
542 0, 0, 0, 0, 0,
543 0, 0,
544 hwdata->div_int >> 4, hwdata->div_int << 4,
545 0
546 };
547
548 regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
549 data, 14);
550
551 /*
552 * Toggle magic bit in undocumented register for unknown reason.
553 * This is what the IDT timing commander tool does and the chip
554 * datasheet somewhat implies this is needed, but the register
555 * and the bit is not documented.
556 */
557 regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
558 VC5_GLOBAL_REGISTER_GLOBAL_RESET, 0);
559 regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
560 VC5_GLOBAL_REGISTER_GLOBAL_RESET,
561 VC5_GLOBAL_REGISTER_GLOBAL_RESET);
562 return 0;
563}
564
565static const struct clk_ops vc5_fod_ops = {
566 .recalc_rate = vc5_fod_recalc_rate,
567 .round_rate = vc5_fod_round_rate,
568 .set_rate = vc5_fod_set_rate,
569};
570
571static int vc5_clk_out_prepare(struct clk_hw *hw)
572{
573 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
574 struct vc5_driver_data *vc5 = hwdata->vc5;
Marek Vasut718f4692017-07-09 15:28:10 +0200575 const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
576 VC5_OUT_DIV_CONTROL_SEL_EXT |
577 VC5_OUT_DIV_CONTROL_EN_FOD;
578 unsigned int src;
579 int ret;
580
581 /*
582 * If the input mux is disabled, enable it first and
583 * select source from matching FOD.
584 */
585 regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
586 if ((src & mask) == 0) {
587 src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD;
588 ret = regmap_update_bits(vc5->regmap,
589 VC5_OUT_DIV_CONTROL(hwdata->num),
590 mask | VC5_OUT_DIV_CONTROL_RESET, src);
591 if (ret)
592 return ret;
593 }
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100594
595 /* Enable the clock buffer */
596 regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
597 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
598 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
599 return 0;
600}
601
602static void vc5_clk_out_unprepare(struct clk_hw *hw)
603{
604 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
605 struct vc5_driver_data *vc5 = hwdata->vc5;
606
Marek Vasuta4decf52017-07-09 15:28:08 +0200607 /* Disable the clock buffer */
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100608 regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
609 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0);
610}
611
612static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
613{
614 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
615 struct vc5_driver_data *vc5 = hwdata->vc5;
616 const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
617 VC5_OUT_DIV_CONTROL_SEL_EXT |
618 VC5_OUT_DIV_CONTROL_EN_FOD;
619 const u8 fodclkmask = VC5_OUT_DIV_CONTROL_SELB_NORM |
620 VC5_OUT_DIV_CONTROL_EN_FOD;
621 const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
622 VC5_OUT_DIV_CONTROL_SEL_EXT;
623 unsigned int src;
624
625 regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
626 src &= mask;
627
Marek Vasut325b7b92017-07-09 15:28:09 +0200628 if (src == 0) /* Input mux set to DISABLED */
629 return 0;
630
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100631 if ((src & fodclkmask) == VC5_OUT_DIV_CONTROL_EN_FOD)
632 return 0;
633
634 if (src == extclk)
635 return 1;
636
637 dev_warn(&vc5->client->dev,
638 "Invalid clock output configuration (%02x)\n", src);
639 return 0;
640}
641
642static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index)
643{
644 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
645 struct vc5_driver_data *vc5 = hwdata->vc5;
646 const u8 mask = VC5_OUT_DIV_CONTROL_RESET |
647 VC5_OUT_DIV_CONTROL_SELB_NORM |
648 VC5_OUT_DIV_CONTROL_SEL_EXT |
649 VC5_OUT_DIV_CONTROL_EN_FOD;
650 const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
651 VC5_OUT_DIV_CONTROL_SEL_EXT;
652 u8 src = VC5_OUT_DIV_CONTROL_RESET;
653
654 if (index == 0)
655 src |= VC5_OUT_DIV_CONTROL_EN_FOD;
656 else
657 src |= extclk;
658
659 return regmap_update_bits(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num),
660 mask, src);
661}
662
663static const struct clk_ops vc5_clk_out_ops = {
664 .prepare = vc5_clk_out_prepare,
665 .unprepare = vc5_clk_out_unprepare,
666 .set_parent = vc5_clk_out_set_parent,
667 .get_parent = vc5_clk_out_get_parent,
668};
669
670static struct clk_hw *vc5_of_clk_get(struct of_phandle_args *clkspec,
671 void *data)
672{
673 struct vc5_driver_data *vc5 = data;
674 unsigned int idx = clkspec->args[0];
675
Alexey Firago9adddb02017-04-07 12:12:22 +0300676 if (idx >= vc5->chip_info->clk_out_cnt)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100677 return ERR_PTR(-EINVAL);
678
679 return &vc5->clk_out[idx].hw;
680}
681
682static int vc5_map_index_to_output(const enum vc5_model model,
683 const unsigned int n)
684{
685 switch (model) {
686 case IDT_VC5_5P49V5933:
687 return (n == 0) ? 0 : 3;
688 case IDT_VC5_5P49V5923:
Alexey Firago1193e142017-04-07 12:12:24 +0300689 case IDT_VC5_5P49V5935:
Marek Vasutdbf6b162017-07-09 15:28:14 +0200690 case IDT_VC6_5P49V6901:
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100691 default:
692 return n;
693 }
694}
695
696static const struct of_device_id clk_vc5_of_match[];
697
698static int vc5_probe(struct i2c_client *client,
699 const struct i2c_device_id *id)
700{
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100701 struct vc5_driver_data *vc5;
702 struct clk_init_data init;
703 const char *parent_names[2];
Alexey Firago9adddb02017-04-07 12:12:22 +0300704 unsigned int n, idx = 0;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100705 int ret;
706
707 vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL);
708 if (vc5 == NULL)
709 return -ENOMEM;
710
711 i2c_set_clientdata(client, vc5);
712 vc5->client = client;
Alexey Firago9adddb02017-04-07 12:12:22 +0300713 vc5->chip_info = of_device_get_match_data(&client->dev);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100714
715 vc5->pin_xin = devm_clk_get(&client->dev, "xin");
716 if (PTR_ERR(vc5->pin_xin) == -EPROBE_DEFER)
717 return -EPROBE_DEFER;
718
719 vc5->pin_clkin = devm_clk_get(&client->dev, "clkin");
720 if (PTR_ERR(vc5->pin_clkin) == -EPROBE_DEFER)
721 return -EPROBE_DEFER;
722
723 vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config);
724 if (IS_ERR(vc5->regmap)) {
725 dev_err(&client->dev, "failed to allocate register map\n");
726 return PTR_ERR(vc5->regmap);
727 }
728
729 /* Register clock input mux */
730 memset(&init, 0, sizeof(init));
731
732 if (!IS_ERR(vc5->pin_xin)) {
733 vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
734 parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin);
Alexey Firago9adddb02017-04-07 12:12:22 +0300735 } else if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) {
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100736 vc5->pin_xin = clk_register_fixed_rate(&client->dev,
737 "internal-xtal", NULL,
738 0, 25000000);
739 if (IS_ERR(vc5->pin_xin))
740 return PTR_ERR(vc5->pin_xin);
741 vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
742 parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin);
743 }
744
745 if (!IS_ERR(vc5->pin_clkin)) {
746 vc5->clk_mux_ins |= VC5_MUX_IN_CLKIN;
747 parent_names[init.num_parents++] =
748 __clk_get_name(vc5->pin_clkin);
749 }
750
751 if (!init.num_parents) {
752 dev_err(&client->dev, "no input clock specified!\n");
753 return -EINVAL;
754 }
755
756 init.name = vc5_mux_names[0];
757 init.ops = &vc5_mux_ops;
758 init.flags = 0;
759 init.parent_names = parent_names;
760 vc5->clk_mux.init = &init;
761 ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
762 if (ret) {
763 dev_err(&client->dev, "unable to register %s\n", init.name);
764 goto err_clk;
765 }
766
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200767 if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
768 /* Register frequency doubler */
769 memset(&init, 0, sizeof(init));
770 init.name = vc5_dbl_names[0];
771 init.ops = &vc5_dbl_ops;
772 init.flags = CLK_SET_RATE_PARENT;
773 init.parent_names = vc5_mux_names;
774 init.num_parents = 1;
775 vc5->clk_mul.init = &init;
776 ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
777 if (ret) {
778 dev_err(&client->dev, "unable to register %s\n",
779 init.name);
780 goto err_clk;
781 }
782 }
783
Marek Vasut55997db2017-07-09 15:28:11 +0200784 /* Register PFD */
785 memset(&init, 0, sizeof(init));
786 init.name = vc5_pfd_names[0];
787 init.ops = &vc5_pfd_ops;
788 init.flags = CLK_SET_RATE_PARENT;
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200789 if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
790 init.parent_names = vc5_dbl_names;
791 else
792 init.parent_names = vc5_mux_names;
Marek Vasut55997db2017-07-09 15:28:11 +0200793 init.num_parents = 1;
794 vc5->clk_pfd.init = &init;
795 ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
796 if (ret) {
797 dev_err(&client->dev, "unable to register %s\n", init.name);
798 goto err_clk;
799 }
800
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100801 /* Register PLL */
802 memset(&init, 0, sizeof(init));
803 init.name = vc5_pll_names[0];
804 init.ops = &vc5_pll_ops;
805 init.flags = CLK_SET_RATE_PARENT;
Marek Vasut55997db2017-07-09 15:28:11 +0200806 init.parent_names = vc5_pfd_names;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100807 init.num_parents = 1;
808 vc5->clk_pll.num = 0;
809 vc5->clk_pll.vc5 = vc5;
810 vc5->clk_pll.hw.init = &init;
811 ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
812 if (ret) {
813 dev_err(&client->dev, "unable to register %s\n", init.name);
814 goto err_clk;
815 }
816
817 /* Register FODs */
Alexey Firago9adddb02017-04-07 12:12:22 +0300818 for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
819 idx = vc5_map_index_to_output(vc5->chip_info->model, n);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100820 memset(&init, 0, sizeof(init));
821 init.name = vc5_fod_names[idx];
822 init.ops = &vc5_fod_ops;
823 init.flags = CLK_SET_RATE_PARENT;
824 init.parent_names = vc5_pll_names;
825 init.num_parents = 1;
826 vc5->clk_fod[n].num = idx;
827 vc5->clk_fod[n].vc5 = vc5;
828 vc5->clk_fod[n].hw.init = &init;
829 ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
830 if (ret) {
831 dev_err(&client->dev, "unable to register %s\n",
832 init.name);
833 goto err_clk;
834 }
835 }
836
837 /* Register MUX-connected OUT0_I2C_SELB output */
838 memset(&init, 0, sizeof(init));
839 init.name = vc5_clk_out_names[0];
840 init.ops = &vc5_clk_out_ops;
841 init.flags = CLK_SET_RATE_PARENT;
842 init.parent_names = vc5_mux_names;
843 init.num_parents = 1;
844 vc5->clk_out[0].num = idx;
845 vc5->clk_out[0].vc5 = vc5;
846 vc5->clk_out[0].hw.init = &init;
847 ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
848 if (ret) {
849 dev_err(&client->dev, "unable to register %s\n",
850 init.name);
851 goto err_clk;
852 }
853
854 /* Register FOD-connected OUTx outputs */
Alexey Firago9adddb02017-04-07 12:12:22 +0300855 for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
856 idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100857 parent_names[0] = vc5_fod_names[idx];
858 if (n == 1)
859 parent_names[1] = vc5_mux_names[0];
860 else
861 parent_names[1] = vc5_clk_out_names[n - 1];
862
863 memset(&init, 0, sizeof(init));
864 init.name = vc5_clk_out_names[idx + 1];
865 init.ops = &vc5_clk_out_ops;
866 init.flags = CLK_SET_RATE_PARENT;
867 init.parent_names = parent_names;
868 init.num_parents = 2;
869 vc5->clk_out[n].num = idx;
870 vc5->clk_out[n].vc5 = vc5;
871 vc5->clk_out[n].hw.init = &init;
872 ret = devm_clk_hw_register(&client->dev,
873 &vc5->clk_out[n].hw);
874 if (ret) {
875 dev_err(&client->dev, "unable to register %s\n",
876 init.name);
877 goto err_clk;
878 }
879 }
880
881 ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
882 if (ret) {
883 dev_err(&client->dev, "unable to add clk provider\n");
884 goto err_clk;
885 }
886
887 return 0;
888
889err_clk:
Alexey Firago9adddb02017-04-07 12:12:22 +0300890 if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100891 clk_unregister_fixed_rate(vc5->pin_xin);
892 return ret;
893}
894
895static int vc5_remove(struct i2c_client *client)
896{
897 struct vc5_driver_data *vc5 = i2c_get_clientdata(client);
898
899 of_clk_del_provider(client->dev.of_node);
900
Alexey Firago9adddb02017-04-07 12:12:22 +0300901 if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100902 clk_unregister_fixed_rate(vc5->pin_xin);
903
904 return 0;
905}
906
Alexey Firago9adddb02017-04-07 12:12:22 +0300907static const struct vc5_chip_info idt_5p49v5923_info = {
908 .model = IDT_VC5_5P49V5923,
909 .clk_fod_cnt = 2,
910 .clk_out_cnt = 3,
911 .flags = 0,
912};
913
914static const struct vc5_chip_info idt_5p49v5933_info = {
915 .model = IDT_VC5_5P49V5933,
916 .clk_fod_cnt = 2,
917 .clk_out_cnt = 3,
918 .flags = VC5_HAS_INTERNAL_XTAL,
919};
920
Alexey Firago1193e142017-04-07 12:12:24 +0300921static const struct vc5_chip_info idt_5p49v5935_info = {
922 .model = IDT_VC5_5P49V5935,
923 .clk_fod_cnt = 4,
924 .clk_out_cnt = 5,
925 .flags = VC5_HAS_INTERNAL_XTAL,
926};
927
Marek Vasutdbf6b162017-07-09 15:28:14 +0200928static const struct vc5_chip_info idt_5p49v6901_info = {
929 .model = IDT_VC6_5P49V6901,
930 .clk_fod_cnt = 4,
931 .clk_out_cnt = 5,
932 .flags = VC5_HAS_PFD_FREQ_DBL,
933};
934
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100935static const struct i2c_device_id vc5_id[] = {
936 { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
937 { "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
Alexey Firago1193e142017-04-07 12:12:24 +0300938 { "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
Marek Vasutdbf6b162017-07-09 15:28:14 +0200939 { "5p49v6901", .driver_data = IDT_VC6_5P49V6901 },
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100940 { }
941};
942MODULE_DEVICE_TABLE(i2c, vc5_id);
943
944static const struct of_device_id clk_vc5_of_match[] = {
Alexey Firago9adddb02017-04-07 12:12:22 +0300945 { .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info },
946 { .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
Alexey Firago1193e142017-04-07 12:12:24 +0300947 { .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
Marek Vasutdbf6b162017-07-09 15:28:14 +0200948 { .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info },
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100949 { },
950};
951MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
952
953static struct i2c_driver vc5_driver = {
954 .driver = {
955 .name = "vc5",
956 .of_match_table = clk_vc5_of_match,
957 },
958 .probe = vc5_probe,
959 .remove = vc5_remove,
960 .id_table = vc5_id,
961};
962module_i2c_driver(vc5_driver);
963
964MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
965MODULE_DESCRIPTION("IDT VersaClock 5 driver");
966MODULE_LICENSE("GPL");