]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/clk/clk-versaclock5.c
clk: vc5: Add bindings for IDT VersaClock 5P49V5935
[mirror_ubuntu-jammy-kernel.git] / drivers / clk / clk-versaclock5.c
CommitLineData
3e1aec4e
MV
1/*
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)
60#define VC5_PRIM_SRC_SHDN_SP BIT(1)
61#define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN BIT(0)
62
63#define VC5_VCO_BAND 0x11
64#define VC5_XTAL_X1_LOAD_CAP 0x12
65#define VC5_XTAL_X2_LOAD_CAP 0x13
66#define VC5_REF_DIVIDER 0x15
67#define VC5_REF_DIVIDER_SEL_PREDIV2 BIT(7)
68#define VC5_REF_DIVIDER_REF_DIV(n) ((n) & 0x3f)
69
70#define VC5_VCO_CTRL_AND_PREDIV 0x16
71#define VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV BIT(7)
72
73#define VC5_FEEDBACK_INT_DIV 0x17
74#define VC5_FEEDBACK_INT_DIV_BITS 0x18
75#define VC5_FEEDBACK_FRAC_DIV(n) (0x19 + (n))
76#define VC5_RC_CONTROL0 0x1e
77#define VC5_RC_CONTROL1 0x1f
78/* Register 0x20 is factory reserved */
79
80/* Output divider control for divider 1,2,3,4 */
81#define VC5_OUT_DIV_CONTROL(idx) (0x21 + ((idx) * 0x10))
82#define VC5_OUT_DIV_CONTROL_RESET BIT(7)
83#define VC5_OUT_DIV_CONTROL_SELB_NORM BIT(3)
84#define VC5_OUT_DIV_CONTROL_SEL_EXT BIT(2)
85#define VC5_OUT_DIV_CONTROL_INT_MODE BIT(1)
86#define VC5_OUT_DIV_CONTROL_EN_FOD BIT(0)
87
88#define VC5_OUT_DIV_FRAC(idx, n) (0x22 + ((idx) * 0x10) + (n))
89#define VC5_OUT_DIV_FRAC4_OD_SCEE BIT(1)
90
91#define VC5_OUT_DIV_STEP_SPREAD(idx, n) (0x26 + ((idx) * 0x10) + (n))
92#define VC5_OUT_DIV_SPREAD_MOD(idx, n) (0x29 + ((idx) * 0x10) + (n))
93#define VC5_OUT_DIV_SKEW_INT(idx, n) (0x2b + ((idx) * 0x10) + (n))
94#define VC5_OUT_DIV_INT(idx, n) (0x2d + ((idx) * 0x10) + (n))
95#define VC5_OUT_DIV_SKEW_FRAC(idx) (0x2f + ((idx) * 0x10))
96/* Registers 0x30, 0x40, 0x50 are factory reserved */
97
98/* Clock control register for clock 1,2 */
99#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
100#define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0)
101
102#define VC5_CLK_OE_SHDN 0x68
103#define VC5_CLK_OS_SHDN 0x69
104
105#define VC5_GLOBAL_REGISTER 0x76
106#define VC5_GLOBAL_REGISTER_GLOBAL_RESET BIT(5)
107
108/* PLL/VCO runs between 2.5 GHz and 3.0 GHz */
109#define VC5_PLL_VCO_MIN 2500000000UL
110#define VC5_PLL_VCO_MAX 3000000000UL
111
112/* VC5 Input mux settings */
113#define VC5_MUX_IN_XIN BIT(0)
114#define VC5_MUX_IN_CLKIN BIT(1)
115
9adddb01
AF
116/* Maximum number of clk_out supported by this driver */
117#define VC5_MAX_CLK_OUT_NUM 3
118
119/* Maximum number of FODs supported by this driver */
120#define VC5_MAX_FOD_NUM 2
121
122/* flags to describe chip features */
123/* chip has built-in oscilator */
124#define VC5_HAS_INTERNAL_XTAL BIT(0)
125
3e1aec4e
MV
126/* Supported IDT VC5 models. */
127enum vc5_model {
128 IDT_VC5_5P49V5923,
129 IDT_VC5_5P49V5933,
130};
131
9adddb01
AF
132/* Structure to describe features of a particular VC5 model */
133struct vc5_chip_info {
134 const enum vc5_model model;
135 const unsigned int clk_fod_cnt;
136 const unsigned int clk_out_cnt;
137 const u32 flags;
138};
139
3e1aec4e
MV
140struct vc5_driver_data;
141
142struct vc5_hw_data {
143 struct clk_hw hw;
144 struct vc5_driver_data *vc5;
145 u32 div_int;
146 u32 div_frc;
147 unsigned int num;
148};
149
150struct vc5_driver_data {
151 struct i2c_client *client;
152 struct regmap *regmap;
9adddb01 153 const struct vc5_chip_info *chip_info;
3e1aec4e
MV
154
155 struct clk *pin_xin;
156 struct clk *pin_clkin;
157 unsigned char clk_mux_ins;
158 struct clk_hw clk_mux;
159 struct vc5_hw_data clk_pll;
9adddb01
AF
160 struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
161 struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
3e1aec4e
MV
162};
163
164static const char * const vc5_mux_names[] = {
165 "mux"
166};
167
168static const char * const vc5_pll_names[] = {
169 "pll"
170};
171
172static const char * const vc5_fod_names[] = {
173 "fod0", "fod1", "fod2", "fod3",
174};
175
176static const char * const vc5_clk_out_names[] = {
177 "out0_sel_i2cb", "out1", "out2", "out3", "out4",
178};
179
180/*
181 * VersaClock5 i2c regmap
182 */
183static bool vc5_regmap_is_writeable(struct device *dev, unsigned int reg)
184{
185 /* Factory reserved regs, make them read-only */
186 if (reg <= 0xf)
187 return false;
188
189 /* Factory reserved regs, make them read-only */
190 if (reg == 0x14 || reg == 0x1c || reg == 0x1d)
191 return false;
192
193 return true;
194}
195
196static const struct regmap_config vc5_regmap_config = {
197 .reg_bits = 8,
198 .val_bits = 8,
199 .cache_type = REGCACHE_RBTREE,
200 .max_register = 0x76,
201 .writeable_reg = vc5_regmap_is_writeable,
202};
203
204/*
205 * VersaClock5 input multiplexer between XTAL and CLKIN divider
206 */
207static unsigned char vc5_mux_get_parent(struct clk_hw *hw)
208{
209 struct vc5_driver_data *vc5 =
210 container_of(hw, struct vc5_driver_data, clk_mux);
211 const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
212 unsigned int src;
213
214 regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src);
215 src &= mask;
216
217 if (src == VC5_PRIM_SRC_SHDN_EN_XTAL)
218 return 0;
219
220 if (src == VC5_PRIM_SRC_SHDN_EN_CLKIN)
221 return 1;
222
223 dev_warn(&vc5->client->dev,
224 "Invalid clock input configuration (%02x)\n", src);
225 return 0;
226}
227
228static int vc5_mux_set_parent(struct clk_hw *hw, u8 index)
229{
230 struct vc5_driver_data *vc5 =
231 container_of(hw, struct vc5_driver_data, clk_mux);
232 const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
233 u8 src;
234
235 if ((index > 1) || !vc5->clk_mux_ins)
236 return -EINVAL;
237
238 if (vc5->clk_mux_ins == (VC5_MUX_IN_CLKIN | VC5_MUX_IN_XIN)) {
239 if (index == 0)
240 src = VC5_PRIM_SRC_SHDN_EN_XTAL;
241 if (index == 1)
242 src = VC5_PRIM_SRC_SHDN_EN_CLKIN;
243 } else {
244 if (index != 0)
245 return -EINVAL;
246
247 if (vc5->clk_mux_ins == VC5_MUX_IN_XIN)
248 src = VC5_PRIM_SRC_SHDN_EN_XTAL;
249 if (vc5->clk_mux_ins == VC5_MUX_IN_CLKIN)
250 src = VC5_PRIM_SRC_SHDN_EN_CLKIN;
251 }
252
253 return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src);
254}
255
256static unsigned long vc5_mux_recalc_rate(struct clk_hw *hw,
257 unsigned long parent_rate)
258{
259 struct vc5_driver_data *vc5 =
260 container_of(hw, struct vc5_driver_data, clk_mux);
261 unsigned int prediv, div;
262
263 regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
264
265 /* The bypass_prediv is set, PLL fed from Ref_in directly. */
266 if (prediv & VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV)
267 return parent_rate;
268
269 regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div);
270
271 /* The Sel_prediv2 is set, PLL fed from prediv2 (Ref_in / 2) */
272 if (div & VC5_REF_DIVIDER_SEL_PREDIV2)
273 return parent_rate / 2;
274 else
275 return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
276}
277
278static long vc5_mux_round_rate(struct clk_hw *hw, unsigned long rate,
279 unsigned long *parent_rate)
280{
281 unsigned long idiv;
282
283 /* PLL cannot operate with input clock above 50 MHz. */
284 if (rate > 50000000)
285 return -EINVAL;
286
287 /* CLKIN within range of PLL input, feed directly to PLL. */
288 if (*parent_rate <= 50000000)
289 return *parent_rate;
290
291 idiv = DIV_ROUND_UP(*parent_rate, rate);
292 if (idiv > 127)
293 return -EINVAL;
294
295 return *parent_rate / idiv;
296}
297
298static int vc5_mux_set_rate(struct clk_hw *hw, unsigned long rate,
299 unsigned long parent_rate)
300{
301 struct vc5_driver_data *vc5 =
302 container_of(hw, struct vc5_driver_data, clk_mux);
303 unsigned long idiv;
304 u8 div;
305
306 /* CLKIN within range of PLL input, feed directly to PLL. */
307 if (parent_rate <= 50000000) {
308 regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
309 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV,
310 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
311 regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00);
312 return 0;
313 }
314
315 idiv = DIV_ROUND_UP(parent_rate, rate);
316
317 /* We have dedicated div-2 predivider. */
318 if (idiv == 2)
319 div = VC5_REF_DIVIDER_SEL_PREDIV2;
320 else
321 div = VC5_REF_DIVIDER_REF_DIV(idiv);
322
323 regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div);
324 regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
325 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, 0);
326
327 return 0;
328}
329
330static const struct clk_ops vc5_mux_ops = {
331 .set_parent = vc5_mux_set_parent,
332 .get_parent = vc5_mux_get_parent,
333 .recalc_rate = vc5_mux_recalc_rate,
334 .round_rate = vc5_mux_round_rate,
335 .set_rate = vc5_mux_set_rate,
336};
337
338/*
339 * VersaClock5 PLL/VCO
340 */
341static unsigned long vc5_pll_recalc_rate(struct clk_hw *hw,
342 unsigned long parent_rate)
343{
344 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
345 struct vc5_driver_data *vc5 = hwdata->vc5;
346 u32 div_int, div_frc;
347 u8 fb[5];
348
349 regmap_bulk_read(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5);
350
351 div_int = (fb[0] << 4) | (fb[1] >> 4);
352 div_frc = (fb[2] << 16) | (fb[3] << 8) | fb[4];
353
354 /* The PLL divider has 12 integer bits and 24 fractional bits */
355 return (parent_rate * div_int) + ((parent_rate * div_frc) >> 24);
356}
357
358static long vc5_pll_round_rate(struct clk_hw *hw, unsigned long rate,
359 unsigned long *parent_rate)
360{
361 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
362 u32 div_int;
363 u64 div_frc;
364
365 if (rate < VC5_PLL_VCO_MIN)
366 rate = VC5_PLL_VCO_MIN;
367 if (rate > VC5_PLL_VCO_MAX)
368 rate = VC5_PLL_VCO_MAX;
369
370 /* Determine integer part, which is 12 bit wide */
371 div_int = rate / *parent_rate;
372 if (div_int > 0xfff)
373 rate = *parent_rate * 0xfff;
374
375 /* Determine best fractional part, which is 24 bit wide */
376 div_frc = rate % *parent_rate;
377 div_frc *= BIT(24) - 1;
378 do_div(div_frc, *parent_rate);
379
380 hwdata->div_int = div_int;
381 hwdata->div_frc = (u32)div_frc;
382
383 return (*parent_rate * div_int) + ((*parent_rate * div_frc) >> 24);
384}
385
386static int vc5_pll_set_rate(struct clk_hw *hw, unsigned long rate,
387 unsigned long parent_rate)
388{
389 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
390 struct vc5_driver_data *vc5 = hwdata->vc5;
391 u8 fb[5];
392
393 fb[0] = hwdata->div_int >> 4;
394 fb[1] = hwdata->div_int << 4;
395 fb[2] = hwdata->div_frc >> 16;
396 fb[3] = hwdata->div_frc >> 8;
397 fb[4] = hwdata->div_frc;
398
399 return regmap_bulk_write(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5);
400}
401
402static const struct clk_ops vc5_pll_ops = {
403 .recalc_rate = vc5_pll_recalc_rate,
404 .round_rate = vc5_pll_round_rate,
405 .set_rate = vc5_pll_set_rate,
406};
407
408static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw,
409 unsigned long parent_rate)
410{
411 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
412 struct vc5_driver_data *vc5 = hwdata->vc5;
413 /* VCO frequency is divided by two before entering FOD */
414 u32 f_in = parent_rate / 2;
415 u32 div_int, div_frc;
416 u8 od_int[2];
417 u8 od_frc[4];
418
419 regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_INT(hwdata->num, 0),
420 od_int, 2);
421 regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
422 od_frc, 4);
423
424 div_int = (od_int[0] << 4) | (od_int[1] >> 4);
425 div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) |
426 (od_frc[2] << 6) | (od_frc[3] >> 2);
427
428 /* The PLL divider has 12 integer bits and 30 fractional bits */
429 return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
430}
431
432static long vc5_fod_round_rate(struct clk_hw *hw, unsigned long rate,
433 unsigned long *parent_rate)
434{
435 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
436 /* VCO frequency is divided by two before entering FOD */
437 u32 f_in = *parent_rate / 2;
438 u32 div_int;
439 u64 div_frc;
440
441 /* Determine integer part, which is 12 bit wide */
442 div_int = f_in / rate;
443 /*
444 * WARNING: The clock chip does not output signal if the integer part
445 * of the divider is 0xfff and fractional part is non-zero.
446 * Clamp the divider at 0xffe to keep the code simple.
447 */
448 if (div_int > 0xffe) {
449 div_int = 0xffe;
450 rate = f_in / div_int;
451 }
452
453 /* Determine best fractional part, which is 30 bit wide */
454 div_frc = f_in % rate;
455 div_frc <<= 24;
456 do_div(div_frc, rate);
457
458 hwdata->div_int = div_int;
459 hwdata->div_frc = (u32)div_frc;
460
461 return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
462}
463
464static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate,
465 unsigned long parent_rate)
466{
467 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
468 struct vc5_driver_data *vc5 = hwdata->vc5;
469 u8 data[14] = {
470 hwdata->div_frc >> 22, hwdata->div_frc >> 14,
471 hwdata->div_frc >> 6, hwdata->div_frc << 2,
472 0, 0, 0, 0, 0,
473 0, 0,
474 hwdata->div_int >> 4, hwdata->div_int << 4,
475 0
476 };
477
478 regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
479 data, 14);
480
481 /*
482 * Toggle magic bit in undocumented register for unknown reason.
483 * This is what the IDT timing commander tool does and the chip
484 * datasheet somewhat implies this is needed, but the register
485 * and the bit is not documented.
486 */
487 regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
488 VC5_GLOBAL_REGISTER_GLOBAL_RESET, 0);
489 regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
490 VC5_GLOBAL_REGISTER_GLOBAL_RESET,
491 VC5_GLOBAL_REGISTER_GLOBAL_RESET);
492 return 0;
493}
494
495static const struct clk_ops vc5_fod_ops = {
496 .recalc_rate = vc5_fod_recalc_rate,
497 .round_rate = vc5_fod_round_rate,
498 .set_rate = vc5_fod_set_rate,
499};
500
501static int vc5_clk_out_prepare(struct clk_hw *hw)
502{
503 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
504 struct vc5_driver_data *vc5 = hwdata->vc5;
505
506 /* Enable the clock buffer */
507 regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
508 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
509 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
510 return 0;
511}
512
513static void vc5_clk_out_unprepare(struct clk_hw *hw)
514{
515 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
516 struct vc5_driver_data *vc5 = hwdata->vc5;
517
518 /* Enable the clock buffer */
519 regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
520 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0);
521}
522
523static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
524{
525 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
526 struct vc5_driver_data *vc5 = hwdata->vc5;
527 const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
528 VC5_OUT_DIV_CONTROL_SEL_EXT |
529 VC5_OUT_DIV_CONTROL_EN_FOD;
530 const u8 fodclkmask = VC5_OUT_DIV_CONTROL_SELB_NORM |
531 VC5_OUT_DIV_CONTROL_EN_FOD;
532 const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
533 VC5_OUT_DIV_CONTROL_SEL_EXT;
534 unsigned int src;
535
536 regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
537 src &= mask;
538
539 if ((src & fodclkmask) == VC5_OUT_DIV_CONTROL_EN_FOD)
540 return 0;
541
542 if (src == extclk)
543 return 1;
544
545 dev_warn(&vc5->client->dev,
546 "Invalid clock output configuration (%02x)\n", src);
547 return 0;
548}
549
550static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index)
551{
552 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
553 struct vc5_driver_data *vc5 = hwdata->vc5;
554 const u8 mask = VC5_OUT_DIV_CONTROL_RESET |
555 VC5_OUT_DIV_CONTROL_SELB_NORM |
556 VC5_OUT_DIV_CONTROL_SEL_EXT |
557 VC5_OUT_DIV_CONTROL_EN_FOD;
558 const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
559 VC5_OUT_DIV_CONTROL_SEL_EXT;
560 u8 src = VC5_OUT_DIV_CONTROL_RESET;
561
562 if (index == 0)
563 src |= VC5_OUT_DIV_CONTROL_EN_FOD;
564 else
565 src |= extclk;
566
567 return regmap_update_bits(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num),
568 mask, src);
569}
570
571static const struct clk_ops vc5_clk_out_ops = {
572 .prepare = vc5_clk_out_prepare,
573 .unprepare = vc5_clk_out_unprepare,
574 .set_parent = vc5_clk_out_set_parent,
575 .get_parent = vc5_clk_out_get_parent,
576};
577
578static struct clk_hw *vc5_of_clk_get(struct of_phandle_args *clkspec,
579 void *data)
580{
581 struct vc5_driver_data *vc5 = data;
582 unsigned int idx = clkspec->args[0];
583
9adddb01 584 if (idx >= vc5->chip_info->clk_out_cnt)
3e1aec4e
MV
585 return ERR_PTR(-EINVAL);
586
587 return &vc5->clk_out[idx].hw;
588}
589
590static int vc5_map_index_to_output(const enum vc5_model model,
591 const unsigned int n)
592{
593 switch (model) {
594 case IDT_VC5_5P49V5933:
595 return (n == 0) ? 0 : 3;
596 case IDT_VC5_5P49V5923:
597 default:
598 return n;
599 }
600}
601
602static const struct of_device_id clk_vc5_of_match[];
603
604static int vc5_probe(struct i2c_client *client,
605 const struct i2c_device_id *id)
606{
3e1aec4e
MV
607 struct vc5_driver_data *vc5;
608 struct clk_init_data init;
609 const char *parent_names[2];
9adddb01 610 unsigned int n, idx = 0;
3e1aec4e
MV
611 int ret;
612
613 vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL);
614 if (vc5 == NULL)
615 return -ENOMEM;
616
617 i2c_set_clientdata(client, vc5);
618 vc5->client = client;
9adddb01 619 vc5->chip_info = of_device_get_match_data(&client->dev);
3e1aec4e
MV
620
621 vc5->pin_xin = devm_clk_get(&client->dev, "xin");
622 if (PTR_ERR(vc5->pin_xin) == -EPROBE_DEFER)
623 return -EPROBE_DEFER;
624
625 vc5->pin_clkin = devm_clk_get(&client->dev, "clkin");
626 if (PTR_ERR(vc5->pin_clkin) == -EPROBE_DEFER)
627 return -EPROBE_DEFER;
628
629 vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config);
630 if (IS_ERR(vc5->regmap)) {
631 dev_err(&client->dev, "failed to allocate register map\n");
632 return PTR_ERR(vc5->regmap);
633 }
634
635 /* Register clock input mux */
636 memset(&init, 0, sizeof(init));
637
638 if (!IS_ERR(vc5->pin_xin)) {
639 vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
640 parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin);
9adddb01 641 } else if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) {
3e1aec4e
MV
642 vc5->pin_xin = clk_register_fixed_rate(&client->dev,
643 "internal-xtal", NULL,
644 0, 25000000);
645 if (IS_ERR(vc5->pin_xin))
646 return PTR_ERR(vc5->pin_xin);
647 vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
648 parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin);
649 }
650
651 if (!IS_ERR(vc5->pin_clkin)) {
652 vc5->clk_mux_ins |= VC5_MUX_IN_CLKIN;
653 parent_names[init.num_parents++] =
654 __clk_get_name(vc5->pin_clkin);
655 }
656
657 if (!init.num_parents) {
658 dev_err(&client->dev, "no input clock specified!\n");
659 return -EINVAL;
660 }
661
662 init.name = vc5_mux_names[0];
663 init.ops = &vc5_mux_ops;
664 init.flags = 0;
665 init.parent_names = parent_names;
666 vc5->clk_mux.init = &init;
667 ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
668 if (ret) {
669 dev_err(&client->dev, "unable to register %s\n", init.name);
670 goto err_clk;
671 }
672
673 /* Register PLL */
674 memset(&init, 0, sizeof(init));
675 init.name = vc5_pll_names[0];
676 init.ops = &vc5_pll_ops;
677 init.flags = CLK_SET_RATE_PARENT;
678 init.parent_names = vc5_mux_names;
679 init.num_parents = 1;
680 vc5->clk_pll.num = 0;
681 vc5->clk_pll.vc5 = vc5;
682 vc5->clk_pll.hw.init = &init;
683 ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
684 if (ret) {
685 dev_err(&client->dev, "unable to register %s\n", init.name);
686 goto err_clk;
687 }
688
689 /* Register FODs */
9adddb01
AF
690 for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
691 idx = vc5_map_index_to_output(vc5->chip_info->model, n);
3e1aec4e
MV
692 memset(&init, 0, sizeof(init));
693 init.name = vc5_fod_names[idx];
694 init.ops = &vc5_fod_ops;
695 init.flags = CLK_SET_RATE_PARENT;
696 init.parent_names = vc5_pll_names;
697 init.num_parents = 1;
698 vc5->clk_fod[n].num = idx;
699 vc5->clk_fod[n].vc5 = vc5;
700 vc5->clk_fod[n].hw.init = &init;
701 ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
702 if (ret) {
703 dev_err(&client->dev, "unable to register %s\n",
704 init.name);
705 goto err_clk;
706 }
707 }
708
709 /* Register MUX-connected OUT0_I2C_SELB output */
710 memset(&init, 0, sizeof(init));
711 init.name = vc5_clk_out_names[0];
712 init.ops = &vc5_clk_out_ops;
713 init.flags = CLK_SET_RATE_PARENT;
714 init.parent_names = vc5_mux_names;
715 init.num_parents = 1;
716 vc5->clk_out[0].num = idx;
717 vc5->clk_out[0].vc5 = vc5;
718 vc5->clk_out[0].hw.init = &init;
719 ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
720 if (ret) {
721 dev_err(&client->dev, "unable to register %s\n",
722 init.name);
723 goto err_clk;
724 }
725
726 /* Register FOD-connected OUTx outputs */
9adddb01
AF
727 for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
728 idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1);
3e1aec4e
MV
729 parent_names[0] = vc5_fod_names[idx];
730 if (n == 1)
731 parent_names[1] = vc5_mux_names[0];
732 else
733 parent_names[1] = vc5_clk_out_names[n - 1];
734
735 memset(&init, 0, sizeof(init));
736 init.name = vc5_clk_out_names[idx + 1];
737 init.ops = &vc5_clk_out_ops;
738 init.flags = CLK_SET_RATE_PARENT;
739 init.parent_names = parent_names;
740 init.num_parents = 2;
741 vc5->clk_out[n].num = idx;
742 vc5->clk_out[n].vc5 = vc5;
743 vc5->clk_out[n].hw.init = &init;
744 ret = devm_clk_hw_register(&client->dev,
745 &vc5->clk_out[n].hw);
746 if (ret) {
747 dev_err(&client->dev, "unable to register %s\n",
748 init.name);
749 goto err_clk;
750 }
751 }
752
753 ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
754 if (ret) {
755 dev_err(&client->dev, "unable to add clk provider\n");
756 goto err_clk;
757 }
758
759 return 0;
760
761err_clk:
9adddb01 762 if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
3e1aec4e
MV
763 clk_unregister_fixed_rate(vc5->pin_xin);
764 return ret;
765}
766
767static int vc5_remove(struct i2c_client *client)
768{
769 struct vc5_driver_data *vc5 = i2c_get_clientdata(client);
770
771 of_clk_del_provider(client->dev.of_node);
772
9adddb01 773 if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
3e1aec4e
MV
774 clk_unregister_fixed_rate(vc5->pin_xin);
775
776 return 0;
777}
778
9adddb01
AF
779static const struct vc5_chip_info idt_5p49v5923_info = {
780 .model = IDT_VC5_5P49V5923,
781 .clk_fod_cnt = 2,
782 .clk_out_cnt = 3,
783 .flags = 0,
784};
785
786static const struct vc5_chip_info idt_5p49v5933_info = {
787 .model = IDT_VC5_5P49V5933,
788 .clk_fod_cnt = 2,
789 .clk_out_cnt = 3,
790 .flags = VC5_HAS_INTERNAL_XTAL,
791};
792
3e1aec4e
MV
793static const struct i2c_device_id vc5_id[] = {
794 { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
795 { "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
796 { }
797};
798MODULE_DEVICE_TABLE(i2c, vc5_id);
799
800static const struct of_device_id clk_vc5_of_match[] = {
9adddb01
AF
801 { .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info },
802 { .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
3e1aec4e
MV
803 { },
804};
805MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
806
807static struct i2c_driver vc5_driver = {
808 .driver = {
809 .name = "vc5",
810 .of_match_table = clk_vc5_of_match,
811 },
812 .probe = vc5_probe,
813 .remove = vc5_remove,
814 .id_table = vc5_id,
815};
816module_i2c_driver(vc5_driver);
817
818MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
819MODULE_DESCRIPTION("IDT VersaClock 5 driver");
820MODULE_LICENSE("GPL");