blob: d6fa15b6f37f297ea94d18110bba4604c9782370 [file] [log] [blame]
Thomas Gleixnerc942fdd2019-05-27 08:55:06 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01002/*
3 * Driver for IDT Versaclock 5
4 *
5 * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01006 */
7
8/*
9 * Possible optimizations:
10 * - Use spread spectrum
11 * - Use integer divider in FOD if applicable
12 */
13
14#include <linux/clk.h>
15#include <linux/clk-provider.h>
16#include <linux/delay.h>
17#include <linux/i2c.h>
18#include <linux/interrupt.h>
19#include <linux/mod_devicetable.h>
20#include <linux/module.h>
21#include <linux/of.h>
22#include <linux/of_platform.h>
23#include <linux/rational.h>
24#include <linux/regmap.h>
25#include <linux/slab.h>
26
Adam Ford260249f2020-06-03 10:43:29 -050027#include <dt-bindings/clk/versaclock.h>
28
Marek Vasut3e1aec4e2017-01-12 02:03:24 +010029/* VersaClock5 registers */
30#define VC5_OTP_CONTROL 0x00
31
32/* Factory-reserved register block */
33#define VC5_RSVD_DEVICE_ID 0x01
34#define VC5_RSVD_ADC_GAIN_7_0 0x02
35#define VC5_RSVD_ADC_GAIN_15_8 0x03
36#define VC5_RSVD_ADC_OFFSET_7_0 0x04
37#define VC5_RSVD_ADC_OFFSET_15_8 0x05
38#define VC5_RSVD_TEMPY 0x06
39#define VC5_RSVD_OFFSET_TBIN 0x07
40#define VC5_RSVD_GAIN 0x08
41#define VC5_RSVD_TEST_NP 0x09
42#define VC5_RSVD_UNUSED 0x0a
43#define VC5_RSVD_BANDGAP_TRIM_UP 0x0b
44#define VC5_RSVD_BANDGAP_TRIM_DN 0x0c
45#define VC5_RSVD_CLK_R_12_CLK_AMP_4 0x0d
46#define VC5_RSVD_CLK_R_34_CLK_AMP_4 0x0e
47#define VC5_RSVD_CLK_AMP_123 0x0f
48
49/* Configuration register block */
50#define VC5_PRIM_SRC_SHDN 0x10
51#define VC5_PRIM_SRC_SHDN_EN_XTAL BIT(7)
52#define VC5_PRIM_SRC_SHDN_EN_CLKIN BIT(6)
Marek Vasut8c1ebe92017-07-09 15:28:12 +020053#define VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ BIT(3)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +010054#define VC5_PRIM_SRC_SHDN_SP BIT(1)
55#define VC5_PRIM_SRC_SHDN_EN_GBL_SHDN BIT(0)
56
57#define VC5_VCO_BAND 0x11
58#define VC5_XTAL_X1_LOAD_CAP 0x12
59#define VC5_XTAL_X2_LOAD_CAP 0x13
60#define VC5_REF_DIVIDER 0x15
61#define VC5_REF_DIVIDER_SEL_PREDIV2 BIT(7)
62#define VC5_REF_DIVIDER_REF_DIV(n) ((n) & 0x3f)
63
64#define VC5_VCO_CTRL_AND_PREDIV 0x16
65#define VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV BIT(7)
66
67#define VC5_FEEDBACK_INT_DIV 0x17
68#define VC5_FEEDBACK_INT_DIV_BITS 0x18
69#define VC5_FEEDBACK_FRAC_DIV(n) (0x19 + (n))
70#define VC5_RC_CONTROL0 0x1e
71#define VC5_RC_CONTROL1 0x1f
72/* Register 0x20 is factory reserved */
73
74/* Output divider control for divider 1,2,3,4 */
75#define VC5_OUT_DIV_CONTROL(idx) (0x21 + ((idx) * 0x10))
76#define VC5_OUT_DIV_CONTROL_RESET BIT(7)
77#define VC5_OUT_DIV_CONTROL_SELB_NORM BIT(3)
78#define VC5_OUT_DIV_CONTROL_SEL_EXT BIT(2)
79#define VC5_OUT_DIV_CONTROL_INT_MODE BIT(1)
80#define VC5_OUT_DIV_CONTROL_EN_FOD BIT(0)
81
82#define VC5_OUT_DIV_FRAC(idx, n) (0x22 + ((idx) * 0x10) + (n))
83#define VC5_OUT_DIV_FRAC4_OD_SCEE BIT(1)
84
85#define VC5_OUT_DIV_STEP_SPREAD(idx, n) (0x26 + ((idx) * 0x10) + (n))
86#define VC5_OUT_DIV_SPREAD_MOD(idx, n) (0x29 + ((idx) * 0x10) + (n))
87#define VC5_OUT_DIV_SKEW_INT(idx, n) (0x2b + ((idx) * 0x10) + (n))
88#define VC5_OUT_DIV_INT(idx, n) (0x2d + ((idx) * 0x10) + (n))
89#define VC5_OUT_DIV_SKEW_FRAC(idx) (0x2f + ((idx) * 0x10))
90/* Registers 0x30, 0x40, 0x50 are factory reserved */
91
92/* Clock control register for clock 1,2 */
93#define VC5_CLK_OUTPUT_CFG(idx, n) (0x60 + ((idx) * 0x2) + (n))
Adam Ford260249f2020-06-03 10:43:29 -050094#define VC5_CLK_OUTPUT_CFG0_CFG_SHIFT 5
95#define VC5_CLK_OUTPUT_CFG0_CFG_MASK GENMASK(7, VC5_CLK_OUTPUT_CFG0_CFG_SHIFT)
96
97#define VC5_CLK_OUTPUT_CFG0_CFG_LVPECL (VC5_LVPECL)
98#define VC5_CLK_OUTPUT_CFG0_CFG_CMOS (VC5_CMOS)
99#define VC5_CLK_OUTPUT_CFG0_CFG_HCSL33 (VC5_HCSL33)
100#define VC5_CLK_OUTPUT_CFG0_CFG_LVDS (VC5_LVDS)
101#define VC5_CLK_OUTPUT_CFG0_CFG_CMOS2 (VC5_CMOS2)
102#define VC5_CLK_OUTPUT_CFG0_CFG_CMOSD (VC5_CMOSD)
103#define VC5_CLK_OUTPUT_CFG0_CFG_HCSL25 (VC5_HCSL25)
104
105#define VC5_CLK_OUTPUT_CFG0_PWR_SHIFT 3
106#define VC5_CLK_OUTPUT_CFG0_PWR_MASK GENMASK(4, VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
107#define VC5_CLK_OUTPUT_CFG0_PWR_18 (0<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
108#define VC5_CLK_OUTPUT_CFG0_PWR_25 (2<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
109#define VC5_CLK_OUTPUT_CFG0_PWR_33 (3<<VC5_CLK_OUTPUT_CFG0_PWR_SHIFT)
110#define VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT 0
111#define VC5_CLK_OUTPUT_CFG0_SLEW_MASK GENMASK(1, VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
112#define VC5_CLK_OUTPUT_CFG0_SLEW_80 (0<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
113#define VC5_CLK_OUTPUT_CFG0_SLEW_85 (1<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
114#define VC5_CLK_OUTPUT_CFG0_SLEW_90 (2<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
115#define VC5_CLK_OUTPUT_CFG0_SLEW_100 (3<<VC5_CLK_OUTPUT_CFG0_SLEW_SHIFT)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100116#define VC5_CLK_OUTPUT_CFG1_EN_CLKBUF BIT(0)
117
118#define VC5_CLK_OE_SHDN 0x68
119#define VC5_CLK_OS_SHDN 0x69
120
121#define VC5_GLOBAL_REGISTER 0x76
122#define VC5_GLOBAL_REGISTER_GLOBAL_RESET BIT(5)
123
124/* PLL/VCO runs between 2.5 GHz and 3.0 GHz */
125#define VC5_PLL_VCO_MIN 2500000000UL
126#define VC5_PLL_VCO_MAX 3000000000UL
127
128/* VC5 Input mux settings */
129#define VC5_MUX_IN_XIN BIT(0)
130#define VC5_MUX_IN_CLKIN BIT(1)
131
Alexey Firago9adddb02017-04-07 12:12:22 +0300132/* Maximum number of clk_out supported by this driver */
Alexey Firago1193e142017-04-07 12:12:24 +0300133#define VC5_MAX_CLK_OUT_NUM 5
Alexey Firago9adddb02017-04-07 12:12:22 +0300134
135/* Maximum number of FODs supported by this driver */
Alexey Firago1193e142017-04-07 12:12:24 +0300136#define VC5_MAX_FOD_NUM 4
Alexey Firago9adddb02017-04-07 12:12:22 +0300137
138/* flags to describe chip features */
139/* chip has built-in oscilator */
140#define VC5_HAS_INTERNAL_XTAL BIT(0)
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200141/* chip has PFD requency doubler */
142#define VC5_HAS_PFD_FREQ_DBL BIT(1)
Alexey Firago9adddb02017-04-07 12:12:22 +0300143
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100144/* Supported IDT VC5 models. */
145enum vc5_model {
146 IDT_VC5_5P49V5923,
Vladimir Barinovb1911552017-07-09 20:39:57 +0300147 IDT_VC5_5P49V5925,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100148 IDT_VC5_5P49V5933,
Alexey Firago1193e142017-04-07 12:12:24 +0300149 IDT_VC5_5P49V5935,
Marek Vasutdbf6b162017-07-09 15:28:14 +0200150 IDT_VC6_5P49V6901,
Adam Ford2bda7482020-04-04 11:15:35 -0500151 IDT_VC6_5P49V6965,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100152};
153
Alexey Firago9adddb02017-04-07 12:12:22 +0300154/* Structure to describe features of a particular VC5 model */
155struct vc5_chip_info {
156 const enum vc5_model model;
157 const unsigned int clk_fod_cnt;
158 const unsigned int clk_out_cnt;
159 const u32 flags;
160};
161
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100162struct vc5_driver_data;
163
164struct vc5_hw_data {
165 struct clk_hw hw;
166 struct vc5_driver_data *vc5;
167 u32 div_int;
168 u32 div_frc;
169 unsigned int num;
Adam Ford260249f2020-06-03 10:43:29 -0500170 unsigned int clk_output_cfg0;
171 unsigned int clk_output_cfg0_mask;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100172};
173
174struct vc5_driver_data {
175 struct i2c_client *client;
176 struct regmap *regmap;
Alexey Firago9adddb02017-04-07 12:12:22 +0300177 const struct vc5_chip_info *chip_info;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100178
179 struct clk *pin_xin;
180 struct clk *pin_clkin;
181 unsigned char clk_mux_ins;
182 struct clk_hw clk_mux;
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200183 struct clk_hw clk_mul;
Marek Vasut55997db2017-07-09 15:28:11 +0200184 struct clk_hw clk_pfd;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100185 struct vc5_hw_data clk_pll;
Alexey Firago9adddb02017-04-07 12:12:22 +0300186 struct vc5_hw_data clk_fod[VC5_MAX_FOD_NUM];
187 struct vc5_hw_data clk_out[VC5_MAX_CLK_OUT_NUM];
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100188};
189
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100190/*
191 * VersaClock5 i2c regmap
192 */
193static bool vc5_regmap_is_writeable(struct device *dev, unsigned int reg)
194{
195 /* Factory reserved regs, make them read-only */
196 if (reg <= 0xf)
197 return false;
198
199 /* Factory reserved regs, make them read-only */
200 if (reg == 0x14 || reg == 0x1c || reg == 0x1d)
201 return false;
202
203 return true;
204}
205
206static const struct regmap_config vc5_regmap_config = {
207 .reg_bits = 8,
208 .val_bits = 8,
209 .cache_type = REGCACHE_RBTREE,
210 .max_register = 0x76,
211 .writeable_reg = vc5_regmap_is_writeable,
212};
213
214/*
215 * VersaClock5 input multiplexer between XTAL and CLKIN divider
216 */
217static unsigned char vc5_mux_get_parent(struct clk_hw *hw)
218{
219 struct vc5_driver_data *vc5 =
220 container_of(hw, struct vc5_driver_data, clk_mux);
221 const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
222 unsigned int src;
223
224 regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src);
225 src &= mask;
226
227 if (src == VC5_PRIM_SRC_SHDN_EN_XTAL)
228 return 0;
229
230 if (src == VC5_PRIM_SRC_SHDN_EN_CLKIN)
231 return 1;
232
233 dev_warn(&vc5->client->dev,
234 "Invalid clock input configuration (%02x)\n", src);
235 return 0;
236}
237
238static int vc5_mux_set_parent(struct clk_hw *hw, u8 index)
239{
240 struct vc5_driver_data *vc5 =
241 container_of(hw, struct vc5_driver_data, clk_mux);
242 const u8 mask = VC5_PRIM_SRC_SHDN_EN_XTAL | VC5_PRIM_SRC_SHDN_EN_CLKIN;
243 u8 src;
244
245 if ((index > 1) || !vc5->clk_mux_ins)
246 return -EINVAL;
247
248 if (vc5->clk_mux_ins == (VC5_MUX_IN_CLKIN | VC5_MUX_IN_XIN)) {
249 if (index == 0)
250 src = VC5_PRIM_SRC_SHDN_EN_XTAL;
251 if (index == 1)
252 src = VC5_PRIM_SRC_SHDN_EN_CLKIN;
253 } else {
254 if (index != 0)
255 return -EINVAL;
256
257 if (vc5->clk_mux_ins == VC5_MUX_IN_XIN)
258 src = VC5_PRIM_SRC_SHDN_EN_XTAL;
Marek Vasut2137a102018-12-15 01:55:19 +0100259 else if (vc5->clk_mux_ins == VC5_MUX_IN_CLKIN)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100260 src = VC5_PRIM_SRC_SHDN_EN_CLKIN;
Marek Vasut2137a102018-12-15 01:55:19 +0100261 else /* Invalid; should have been caught by vc5_probe() */
262 return -EINVAL;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100263 }
264
265 return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src);
266}
267
Marek Vasut55997db2017-07-09 15:28:11 +0200268static const struct clk_ops vc5_mux_ops = {
269 .set_parent = vc5_mux_set_parent,
270 .get_parent = vc5_mux_get_parent,
271};
272
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200273static unsigned long vc5_dbl_recalc_rate(struct clk_hw *hw,
274 unsigned long parent_rate)
275{
276 struct vc5_driver_data *vc5 =
277 container_of(hw, struct vc5_driver_data, clk_mul);
278 unsigned int premul;
279
280 regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul);
281 if (premul & VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ)
282 parent_rate *= 2;
283
284 return parent_rate;
285}
286
287static long vc5_dbl_round_rate(struct clk_hw *hw, unsigned long rate,
288 unsigned long *parent_rate)
289{
290 if ((*parent_rate == rate) || ((*parent_rate * 2) == rate))
291 return rate;
292 else
293 return -EINVAL;
294}
295
296static int vc5_dbl_set_rate(struct clk_hw *hw, unsigned long rate,
297 unsigned long parent_rate)
298{
299 struct vc5_driver_data *vc5 =
300 container_of(hw, struct vc5_driver_data, clk_mul);
301 u32 mask;
302
303 if ((parent_rate * 2) == rate)
304 mask = VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ;
305 else
306 mask = 0;
307
308 regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN,
309 VC5_PRIM_SRC_SHDN_EN_DOUBLE_XTAL_FREQ,
310 mask);
311
312 return 0;
313}
314
315static const struct clk_ops vc5_dbl_ops = {
316 .recalc_rate = vc5_dbl_recalc_rate,
317 .round_rate = vc5_dbl_round_rate,
318 .set_rate = vc5_dbl_set_rate,
319};
320
Marek Vasut55997db2017-07-09 15:28:11 +0200321static unsigned long vc5_pfd_recalc_rate(struct clk_hw *hw,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100322 unsigned long parent_rate)
323{
324 struct vc5_driver_data *vc5 =
Marek Vasut55997db2017-07-09 15:28:11 +0200325 container_of(hw, struct vc5_driver_data, clk_pfd);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100326 unsigned int prediv, div;
327
328 regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv);
329
330 /* The bypass_prediv is set, PLL fed from Ref_in directly. */
331 if (prediv & VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV)
332 return parent_rate;
333
334 regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div);
335
336 /* The Sel_prediv2 is set, PLL fed from prediv2 (Ref_in / 2) */
337 if (div & VC5_REF_DIVIDER_SEL_PREDIV2)
338 return parent_rate / 2;
339 else
340 return parent_rate / VC5_REF_DIVIDER_REF_DIV(div);
341}
342
Marek Vasut55997db2017-07-09 15:28:11 +0200343static long vc5_pfd_round_rate(struct clk_hw *hw, unsigned long rate,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100344 unsigned long *parent_rate)
345{
346 unsigned long idiv;
347
348 /* PLL cannot operate with input clock above 50 MHz. */
349 if (rate > 50000000)
350 return -EINVAL;
351
352 /* CLKIN within range of PLL input, feed directly to PLL. */
353 if (*parent_rate <= 50000000)
354 return *parent_rate;
355
356 idiv = DIV_ROUND_UP(*parent_rate, rate);
357 if (idiv > 127)
358 return -EINVAL;
359
360 return *parent_rate / idiv;
361}
362
Marek Vasut55997db2017-07-09 15:28:11 +0200363static int vc5_pfd_set_rate(struct clk_hw *hw, unsigned long rate,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100364 unsigned long parent_rate)
365{
366 struct vc5_driver_data *vc5 =
Marek Vasut55997db2017-07-09 15:28:11 +0200367 container_of(hw, struct vc5_driver_data, clk_pfd);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100368 unsigned long idiv;
369 u8 div;
370
371 /* CLKIN within range of PLL input, feed directly to PLL. */
372 if (parent_rate <= 50000000) {
373 regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
374 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV,
375 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV);
376 regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00);
377 return 0;
378 }
379
380 idiv = DIV_ROUND_UP(parent_rate, rate);
381
382 /* We have dedicated div-2 predivider. */
383 if (idiv == 2)
384 div = VC5_REF_DIVIDER_SEL_PREDIV2;
385 else
386 div = VC5_REF_DIVIDER_REF_DIV(idiv);
387
388 regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div);
389 regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV,
390 VC5_VCO_CTRL_AND_PREDIV_BYPASS_PREDIV, 0);
391
392 return 0;
393}
394
Marek Vasut55997db2017-07-09 15:28:11 +0200395static const struct clk_ops vc5_pfd_ops = {
396 .recalc_rate = vc5_pfd_recalc_rate,
397 .round_rate = vc5_pfd_round_rate,
398 .set_rate = vc5_pfd_set_rate,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100399};
400
401/*
402 * VersaClock5 PLL/VCO
403 */
404static unsigned long vc5_pll_recalc_rate(struct clk_hw *hw,
405 unsigned long parent_rate)
406{
407 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
408 struct vc5_driver_data *vc5 = hwdata->vc5;
409 u32 div_int, div_frc;
410 u8 fb[5];
411
412 regmap_bulk_read(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5);
413
414 div_int = (fb[0] << 4) | (fb[1] >> 4);
415 div_frc = (fb[2] << 16) | (fb[3] << 8) | fb[4];
416
417 /* The PLL divider has 12 integer bits and 24 fractional bits */
418 return (parent_rate * div_int) + ((parent_rate * div_frc) >> 24);
419}
420
421static long vc5_pll_round_rate(struct clk_hw *hw, unsigned long rate,
422 unsigned long *parent_rate)
423{
424 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
425 u32 div_int;
426 u64 div_frc;
427
428 if (rate < VC5_PLL_VCO_MIN)
429 rate = VC5_PLL_VCO_MIN;
430 if (rate > VC5_PLL_VCO_MAX)
431 rate = VC5_PLL_VCO_MAX;
432
433 /* Determine integer part, which is 12 bit wide */
434 div_int = rate / *parent_rate;
435 if (div_int > 0xfff)
436 rate = *parent_rate * 0xfff;
437
438 /* Determine best fractional part, which is 24 bit wide */
439 div_frc = rate % *parent_rate;
440 div_frc *= BIT(24) - 1;
441 do_div(div_frc, *parent_rate);
442
443 hwdata->div_int = div_int;
444 hwdata->div_frc = (u32)div_frc;
445
446 return (*parent_rate * div_int) + ((*parent_rate * div_frc) >> 24);
447}
448
449static int vc5_pll_set_rate(struct clk_hw *hw, unsigned long rate,
450 unsigned long parent_rate)
451{
452 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
453 struct vc5_driver_data *vc5 = hwdata->vc5;
454 u8 fb[5];
455
456 fb[0] = hwdata->div_int >> 4;
457 fb[1] = hwdata->div_int << 4;
458 fb[2] = hwdata->div_frc >> 16;
459 fb[3] = hwdata->div_frc >> 8;
460 fb[4] = hwdata->div_frc;
461
462 return regmap_bulk_write(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5);
463}
464
465static const struct clk_ops vc5_pll_ops = {
466 .recalc_rate = vc5_pll_recalc_rate,
467 .round_rate = vc5_pll_round_rate,
468 .set_rate = vc5_pll_set_rate,
469};
470
471static unsigned long vc5_fod_recalc_rate(struct clk_hw *hw,
472 unsigned long parent_rate)
473{
474 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
475 struct vc5_driver_data *vc5 = hwdata->vc5;
476 /* VCO frequency is divided by two before entering FOD */
477 u32 f_in = parent_rate / 2;
478 u32 div_int, div_frc;
479 u8 od_int[2];
480 u8 od_frc[4];
481
482 regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_INT(hwdata->num, 0),
483 od_int, 2);
484 regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
485 od_frc, 4);
486
487 div_int = (od_int[0] << 4) | (od_int[1] >> 4);
488 div_frc = (od_frc[0] << 22) | (od_frc[1] << 14) |
489 (od_frc[2] << 6) | (od_frc[3] >> 2);
490
Marek Vasut3bded562017-07-09 15:28:07 +0200491 /* Avoid division by zero if the output is not configured. */
492 if (div_int == 0 && div_frc == 0)
493 return 0;
494
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100495 /* The PLL divider has 12 integer bits and 30 fractional bits */
496 return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
497}
498
499static long vc5_fod_round_rate(struct clk_hw *hw, unsigned long rate,
500 unsigned long *parent_rate)
501{
502 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
503 /* VCO frequency is divided by two before entering FOD */
504 u32 f_in = *parent_rate / 2;
505 u32 div_int;
506 u64 div_frc;
507
508 /* Determine integer part, which is 12 bit wide */
509 div_int = f_in / rate;
510 /*
511 * WARNING: The clock chip does not output signal if the integer part
512 * of the divider is 0xfff and fractional part is non-zero.
513 * Clamp the divider at 0xffe to keep the code simple.
514 */
515 if (div_int > 0xffe) {
516 div_int = 0xffe;
517 rate = f_in / div_int;
518 }
519
520 /* Determine best fractional part, which is 30 bit wide */
521 div_frc = f_in % rate;
522 div_frc <<= 24;
523 do_div(div_frc, rate);
524
525 hwdata->div_int = div_int;
526 hwdata->div_frc = (u32)div_frc;
527
528 return div64_u64((u64)f_in << 24ULL, ((u64)div_int << 24ULL) + div_frc);
529}
530
531static int vc5_fod_set_rate(struct clk_hw *hw, unsigned long rate,
532 unsigned long parent_rate)
533{
534 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
535 struct vc5_driver_data *vc5 = hwdata->vc5;
536 u8 data[14] = {
537 hwdata->div_frc >> 22, hwdata->div_frc >> 14,
538 hwdata->div_frc >> 6, hwdata->div_frc << 2,
539 0, 0, 0, 0, 0,
540 0, 0,
541 hwdata->div_int >> 4, hwdata->div_int << 4,
542 0
543 };
544
545 regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0),
546 data, 14);
547
548 /*
549 * Toggle magic bit in undocumented register for unknown reason.
550 * This is what the IDT timing commander tool does and the chip
551 * datasheet somewhat implies this is needed, but the register
552 * and the bit is not documented.
553 */
554 regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
555 VC5_GLOBAL_REGISTER_GLOBAL_RESET, 0);
556 regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER,
557 VC5_GLOBAL_REGISTER_GLOBAL_RESET,
558 VC5_GLOBAL_REGISTER_GLOBAL_RESET);
559 return 0;
560}
561
562static const struct clk_ops vc5_fod_ops = {
563 .recalc_rate = vc5_fod_recalc_rate,
564 .round_rate = vc5_fod_round_rate,
565 .set_rate = vc5_fod_set_rate,
566};
567
568static int vc5_clk_out_prepare(struct clk_hw *hw)
569{
570 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
571 struct vc5_driver_data *vc5 = hwdata->vc5;
Marek Vasut718f4692017-07-09 15:28:10 +0200572 const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
573 VC5_OUT_DIV_CONTROL_SEL_EXT |
574 VC5_OUT_DIV_CONTROL_EN_FOD;
575 unsigned int src;
576 int ret;
577
578 /*
579 * If the input mux is disabled, enable it first and
580 * select source from matching FOD.
581 */
582 regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
583 if ((src & mask) == 0) {
584 src = VC5_OUT_DIV_CONTROL_RESET | VC5_OUT_DIV_CONTROL_EN_FOD;
585 ret = regmap_update_bits(vc5->regmap,
586 VC5_OUT_DIV_CONTROL(hwdata->num),
587 mask | VC5_OUT_DIV_CONTROL_RESET, src);
588 if (ret)
589 return ret;
590 }
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100591
592 /* Enable the clock buffer */
593 regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
594 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF,
595 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF);
Adam Ford260249f2020-06-03 10:43:29 -0500596 if (hwdata->clk_output_cfg0_mask) {
597 dev_dbg(&vc5->client->dev, "Update output %d mask 0x%0X val 0x%0X\n",
598 hwdata->num, hwdata->clk_output_cfg0_mask,
599 hwdata->clk_output_cfg0);
600
601 regmap_update_bits(vc5->regmap,
602 VC5_CLK_OUTPUT_CFG(hwdata->num, 0),
603 hwdata->clk_output_cfg0_mask,
604 hwdata->clk_output_cfg0);
605 }
606
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100607 return 0;
608}
609
610static void vc5_clk_out_unprepare(struct clk_hw *hw)
611{
612 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
613 struct vc5_driver_data *vc5 = hwdata->vc5;
614
Marek Vasuta4decf52017-07-09 15:28:08 +0200615 /* Disable the clock buffer */
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100616 regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1),
617 VC5_CLK_OUTPUT_CFG1_EN_CLKBUF, 0);
618}
619
620static unsigned char vc5_clk_out_get_parent(struct clk_hw *hw)
621{
622 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
623 struct vc5_driver_data *vc5 = hwdata->vc5;
624 const u8 mask = VC5_OUT_DIV_CONTROL_SELB_NORM |
625 VC5_OUT_DIV_CONTROL_SEL_EXT |
626 VC5_OUT_DIV_CONTROL_EN_FOD;
627 const u8 fodclkmask = VC5_OUT_DIV_CONTROL_SELB_NORM |
628 VC5_OUT_DIV_CONTROL_EN_FOD;
629 const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
630 VC5_OUT_DIV_CONTROL_SEL_EXT;
631 unsigned int src;
632
633 regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src);
634 src &= mask;
635
Marek Vasut325b7b92017-07-09 15:28:09 +0200636 if (src == 0) /* Input mux set to DISABLED */
637 return 0;
638
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100639 if ((src & fodclkmask) == VC5_OUT_DIV_CONTROL_EN_FOD)
640 return 0;
641
642 if (src == extclk)
643 return 1;
644
645 dev_warn(&vc5->client->dev,
646 "Invalid clock output configuration (%02x)\n", src);
647 return 0;
648}
649
650static int vc5_clk_out_set_parent(struct clk_hw *hw, u8 index)
651{
652 struct vc5_hw_data *hwdata = container_of(hw, struct vc5_hw_data, hw);
653 struct vc5_driver_data *vc5 = hwdata->vc5;
654 const u8 mask = VC5_OUT_DIV_CONTROL_RESET |
655 VC5_OUT_DIV_CONTROL_SELB_NORM |
656 VC5_OUT_DIV_CONTROL_SEL_EXT |
657 VC5_OUT_DIV_CONTROL_EN_FOD;
658 const u8 extclk = VC5_OUT_DIV_CONTROL_SELB_NORM |
659 VC5_OUT_DIV_CONTROL_SEL_EXT;
660 u8 src = VC5_OUT_DIV_CONTROL_RESET;
661
662 if (index == 0)
663 src |= VC5_OUT_DIV_CONTROL_EN_FOD;
664 else
665 src |= extclk;
666
667 return regmap_update_bits(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num),
668 mask, src);
669}
670
671static const struct clk_ops vc5_clk_out_ops = {
672 .prepare = vc5_clk_out_prepare,
673 .unprepare = vc5_clk_out_unprepare,
674 .set_parent = vc5_clk_out_set_parent,
675 .get_parent = vc5_clk_out_get_parent,
676};
677
678static struct clk_hw *vc5_of_clk_get(struct of_phandle_args *clkspec,
679 void *data)
680{
681 struct vc5_driver_data *vc5 = data;
682 unsigned int idx = clkspec->args[0];
683
Alexey Firago9adddb02017-04-07 12:12:22 +0300684 if (idx >= vc5->chip_info->clk_out_cnt)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100685 return ERR_PTR(-EINVAL);
686
687 return &vc5->clk_out[idx].hw;
688}
689
690static int vc5_map_index_to_output(const enum vc5_model model,
691 const unsigned int n)
692{
693 switch (model) {
694 case IDT_VC5_5P49V5933:
695 return (n == 0) ? 0 : 3;
696 case IDT_VC5_5P49V5923:
Vladimir Barinovb1911552017-07-09 20:39:57 +0300697 case IDT_VC5_5P49V5925:
Alexey Firago1193e142017-04-07 12:12:24 +0300698 case IDT_VC5_5P49V5935:
Marek Vasutdbf6b162017-07-09 15:28:14 +0200699 case IDT_VC6_5P49V6901:
Adam Ford2bda7482020-04-04 11:15:35 -0500700 case IDT_VC6_5P49V6965:
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100701 default:
702 return n;
703 }
704}
705
Adam Ford260249f2020-06-03 10:43:29 -0500706static int vc5_update_mode(struct device_node *np_output,
707 struct vc5_hw_data *clk_out)
708{
709 u32 value;
710
711 if (!of_property_read_u32(np_output, "idt,mode", &value)) {
712 clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_CFG_MASK;
713 switch (value) {
714 case VC5_CLK_OUTPUT_CFG0_CFG_LVPECL:
715 case VC5_CLK_OUTPUT_CFG0_CFG_CMOS:
716 case VC5_CLK_OUTPUT_CFG0_CFG_HCSL33:
717 case VC5_CLK_OUTPUT_CFG0_CFG_LVDS:
718 case VC5_CLK_OUTPUT_CFG0_CFG_CMOS2:
719 case VC5_CLK_OUTPUT_CFG0_CFG_CMOSD:
720 case VC5_CLK_OUTPUT_CFG0_CFG_HCSL25:
721 clk_out->clk_output_cfg0 |=
722 value << VC5_CLK_OUTPUT_CFG0_CFG_SHIFT;
723 break;
724 default:
725 return -EINVAL;
726 }
727 }
728 return 0;
729}
730
731static int vc5_update_power(struct device_node *np_output,
732 struct vc5_hw_data *clk_out)
733{
734 u32 value;
735
736 if (!of_property_read_u32(np_output,
737 "idt,voltage-microvolts", &value)) {
738 clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_PWR_MASK;
739 switch (value) {
740 case 1800000:
741 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_18;
742 break;
743 case 2500000:
744 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_25;
745 break;
746 case 3300000:
747 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_33;
748 break;
749 default:
750 return -EINVAL;
751 }
752 }
753 return 0;
754}
755
756static int vc5_update_slew(struct device_node *np_output,
757 struct vc5_hw_data *clk_out)
758{
759 u32 value;
760
761 if (!of_property_read_u32(np_output, "idt,slew-percent", &value)) {
762 clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_SLEW_MASK;
763 switch (value) {
764 case 80:
765 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_80;
766 break;
767 case 85:
768 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_85;
769 break;
770 case 90:
771 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_90;
772 break;
773 case 100:
774 clk_out->clk_output_cfg0 |=
775 VC5_CLK_OUTPUT_CFG0_SLEW_100;
776 break;
777 default:
778 return -EINVAL;
779 }
780 }
781 return 0;
782}
783
784static int vc5_get_output_config(struct i2c_client *client,
785 struct vc5_hw_data *clk_out)
786{
787 struct device_node *np_output;
788 char *child_name;
789 int ret = 0;
790
791 child_name = kasprintf(GFP_KERNEL, "OUT%d", clk_out->num + 1);
792 np_output = of_get_child_by_name(client->dev.of_node, child_name);
793 kfree(child_name);
794 if (!np_output)
795 goto output_done;
796
797 ret = vc5_update_mode(np_output, clk_out);
798 if (ret)
799 goto output_error;
800
801 ret = vc5_update_power(np_output, clk_out);
802 if (ret)
803 goto output_error;
804
805 ret = vc5_update_slew(np_output, clk_out);
806
807output_error:
808 if (ret) {
809 dev_err(&client->dev,
810 "Invalid clock output configuration OUT%d\n",
811 clk_out->num + 1);
812 }
813
814 of_node_put(np_output);
815
816output_done:
817 return ret;
818}
819
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100820static const struct of_device_id clk_vc5_of_match[];
821
Adam Fordf4912762020-06-03 10:43:27 -0500822static int vc5_probe(struct i2c_client *client, const struct i2c_device_id *id)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100823{
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100824 struct vc5_driver_data *vc5;
825 struct clk_init_data init;
826 const char *parent_names[2];
Alexey Firago9adddb02017-04-07 12:12:22 +0300827 unsigned int n, idx = 0;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100828 int ret;
829
830 vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL);
831 if (vc5 == NULL)
832 return -ENOMEM;
833
834 i2c_set_clientdata(client, vc5);
835 vc5->client = client;
Alexey Firago9adddb02017-04-07 12:12:22 +0300836 vc5->chip_info = of_device_get_match_data(&client->dev);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100837
838 vc5->pin_xin = devm_clk_get(&client->dev, "xin");
839 if (PTR_ERR(vc5->pin_xin) == -EPROBE_DEFER)
840 return -EPROBE_DEFER;
841
842 vc5->pin_clkin = devm_clk_get(&client->dev, "clkin");
843 if (PTR_ERR(vc5->pin_clkin) == -EPROBE_DEFER)
844 return -EPROBE_DEFER;
845
846 vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config);
847 if (IS_ERR(vc5->regmap)) {
848 dev_err(&client->dev, "failed to allocate register map\n");
849 return PTR_ERR(vc5->regmap);
850 }
851
852 /* Register clock input mux */
853 memset(&init, 0, sizeof(init));
854
855 if (!IS_ERR(vc5->pin_xin)) {
856 vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
857 parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin);
Alexey Firago9adddb02017-04-07 12:12:22 +0300858 } else if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) {
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100859 vc5->pin_xin = clk_register_fixed_rate(&client->dev,
860 "internal-xtal", NULL,
861 0, 25000000);
862 if (IS_ERR(vc5->pin_xin))
863 return PTR_ERR(vc5->pin_xin);
864 vc5->clk_mux_ins |= VC5_MUX_IN_XIN;
865 parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin);
866 }
867
868 if (!IS_ERR(vc5->pin_clkin)) {
869 vc5->clk_mux_ins |= VC5_MUX_IN_CLKIN;
870 parent_names[init.num_parents++] =
Adam Fordf4912762020-06-03 10:43:27 -0500871 __clk_get_name(vc5->pin_clkin);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100872 }
873
874 if (!init.num_parents) {
875 dev_err(&client->dev, "no input clock specified!\n");
876 return -EINVAL;
877 }
878
Adam Fordf4912762020-06-03 10:43:27 -0500879 init.name = kasprintf(GFP_KERNEL, "%pOFn.mux", client->dev.of_node);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100880 init.ops = &vc5_mux_ops;
881 init.flags = 0;
882 init.parent_names = parent_names;
883 vc5->clk_mux.init = &init;
884 ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux);
Colin Ian King82005972020-06-25 14:27:36 +0100885 if (ret)
886 goto err_clk_register;
Adam Fordf4912762020-06-03 10:43:27 -0500887 kfree(init.name); /* clock framework made a copy of the name */
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100888
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200889 if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) {
890 /* Register frequency doubler */
891 memset(&init, 0, sizeof(init));
Adam Fordf4912762020-06-03 10:43:27 -0500892 init.name = kasprintf(GFP_KERNEL, "%pOFn.dbl",
893 client->dev.of_node);
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200894 init.ops = &vc5_dbl_ops;
895 init.flags = CLK_SET_RATE_PARENT;
Adam Fordf4912762020-06-03 10:43:27 -0500896 init.parent_names = parent_names;
897 parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200898 init.num_parents = 1;
899 vc5->clk_mul.init = &init;
900 ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul);
Colin Ian King82005972020-06-25 14:27:36 +0100901 if (ret)
902 goto err_clk_register;
Adam Fordf4912762020-06-03 10:43:27 -0500903 kfree(init.name); /* clock framework made a copy of the name */
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200904 }
905
Marek Vasut55997db2017-07-09 15:28:11 +0200906 /* Register PFD */
907 memset(&init, 0, sizeof(init));
Adam Fordf4912762020-06-03 10:43:27 -0500908 init.name = kasprintf(GFP_KERNEL, "%pOFn.pfd", client->dev.of_node);
Marek Vasut55997db2017-07-09 15:28:11 +0200909 init.ops = &vc5_pfd_ops;
910 init.flags = CLK_SET_RATE_PARENT;
Adam Fordf4912762020-06-03 10:43:27 -0500911 init.parent_names = parent_names;
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200912 if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL)
Adam Fordf4912762020-06-03 10:43:27 -0500913 parent_names[0] = clk_hw_get_name(&vc5->clk_mul);
Marek Vasut8c1ebe92017-07-09 15:28:12 +0200914 else
Adam Fordf4912762020-06-03 10:43:27 -0500915 parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
Marek Vasut55997db2017-07-09 15:28:11 +0200916 init.num_parents = 1;
917 vc5->clk_pfd.init = &init;
918 ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd);
Colin Ian King82005972020-06-25 14:27:36 +0100919 if (ret)
920 goto err_clk_register;
Adam Fordf4912762020-06-03 10:43:27 -0500921 kfree(init.name); /* clock framework made a copy of the name */
Marek Vasut55997db2017-07-09 15:28:11 +0200922
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100923 /* Register PLL */
924 memset(&init, 0, sizeof(init));
Adam Fordf4912762020-06-03 10:43:27 -0500925 init.name = kasprintf(GFP_KERNEL, "%pOFn.pll", client->dev.of_node);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100926 init.ops = &vc5_pll_ops;
927 init.flags = CLK_SET_RATE_PARENT;
Adam Fordf4912762020-06-03 10:43:27 -0500928 init.parent_names = parent_names;
929 parent_names[0] = clk_hw_get_name(&vc5->clk_pfd);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100930 init.num_parents = 1;
931 vc5->clk_pll.num = 0;
932 vc5->clk_pll.vc5 = vc5;
933 vc5->clk_pll.hw.init = &init;
934 ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw);
Colin Ian King82005972020-06-25 14:27:36 +0100935 if (ret)
936 goto err_clk_register;
Adam Fordf4912762020-06-03 10:43:27 -0500937 kfree(init.name); /* clock framework made a copy of the name */
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100938
939 /* Register FODs */
Alexey Firago9adddb02017-04-07 12:12:22 +0300940 for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) {
941 idx = vc5_map_index_to_output(vc5->chip_info->model, n);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100942 memset(&init, 0, sizeof(init));
Adam Fordf4912762020-06-03 10:43:27 -0500943 init.name = kasprintf(GFP_KERNEL, "%pOFn.fod%d",
944 client->dev.of_node, idx);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100945 init.ops = &vc5_fod_ops;
946 init.flags = CLK_SET_RATE_PARENT;
Adam Fordf4912762020-06-03 10:43:27 -0500947 init.parent_names = parent_names;
948 parent_names[0] = clk_hw_get_name(&vc5->clk_pll.hw);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100949 init.num_parents = 1;
950 vc5->clk_fod[n].num = idx;
951 vc5->clk_fod[n].vc5 = vc5;
952 vc5->clk_fod[n].hw.init = &init;
953 ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw);
Colin Ian King82005972020-06-25 14:27:36 +0100954 if (ret)
955 goto err_clk_register;
Adam Fordf4912762020-06-03 10:43:27 -0500956 kfree(init.name); /* clock framework made a copy of the name */
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100957 }
958
959 /* Register MUX-connected OUT0_I2C_SELB output */
960 memset(&init, 0, sizeof(init));
Adam Fordf4912762020-06-03 10:43:27 -0500961 init.name = kasprintf(GFP_KERNEL, "%pOFn.out0_sel_i2cb",
962 client->dev.of_node);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100963 init.ops = &vc5_clk_out_ops;
964 init.flags = CLK_SET_RATE_PARENT;
Adam Fordf4912762020-06-03 10:43:27 -0500965 init.parent_names = parent_names;
966 parent_names[0] = clk_hw_get_name(&vc5->clk_mux);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100967 init.num_parents = 1;
968 vc5->clk_out[0].num = idx;
969 vc5->clk_out[0].vc5 = vc5;
970 vc5->clk_out[0].hw.init = &init;
971 ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw);
Colin Ian King82005972020-06-25 14:27:36 +0100972 if (ret)
973 goto err_clk_register;
974 kfree(init.name); /* clock framework made a copy of the name */
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100975
976 /* Register FOD-connected OUTx outputs */
Alexey Firago9adddb02017-04-07 12:12:22 +0300977 for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) {
978 idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1);
Adam Fordf4912762020-06-03 10:43:27 -0500979 parent_names[0] = clk_hw_get_name(&vc5->clk_fod[idx].hw);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100980 if (n == 1)
Adam Fordf4912762020-06-03 10:43:27 -0500981 parent_names[1] = clk_hw_get_name(&vc5->clk_mux);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100982 else
Adam Fordf4912762020-06-03 10:43:27 -0500983 parent_names[1] =
984 clk_hw_get_name(&vc5->clk_out[n - 1].hw);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100985
986 memset(&init, 0, sizeof(init));
Adam Fordf4912762020-06-03 10:43:27 -0500987 init.name = kasprintf(GFP_KERNEL, "%pOFn.out%d",
988 client->dev.of_node, idx + 1);
Marek Vasut3e1aec4e2017-01-12 02:03:24 +0100989 init.ops = &vc5_clk_out_ops;
990 init.flags = CLK_SET_RATE_PARENT;
991 init.parent_names = parent_names;
992 init.num_parents = 2;
993 vc5->clk_out[n].num = idx;
994 vc5->clk_out[n].vc5 = vc5;
995 vc5->clk_out[n].hw.init = &init;
Adam Fordf4912762020-06-03 10:43:27 -0500996 ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw);
Colin Ian King82005972020-06-25 14:27:36 +0100997 if (ret)
998 goto err_clk_register;
Adam Fordf4912762020-06-03 10:43:27 -0500999 kfree(init.name); /* clock framework made a copy of the name */
Adam Ford260249f2020-06-03 10:43:29 -05001000
1001 /* Fetch Clock Output configuration from DT (if specified) */
1002 ret = vc5_get_output_config(client, &vc5->clk_out[n]);
1003 if (ret)
1004 goto err_clk;
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001005 }
1006
1007 ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5);
1008 if (ret) {
1009 dev_err(&client->dev, "unable to add clk provider\n");
1010 goto err_clk;
1011 }
1012
1013 return 0;
1014
Colin Ian King82005972020-06-25 14:27:36 +01001015err_clk_register:
1016 dev_err(&client->dev, "unable to register %s\n", init.name);
1017 kfree(init.name); /* clock framework made a copy of the name */
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001018err_clk:
Alexey Firago9adddb02017-04-07 12:12:22 +03001019 if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001020 clk_unregister_fixed_rate(vc5->pin_xin);
1021 return ret;
1022}
1023
1024static int vc5_remove(struct i2c_client *client)
1025{
1026 struct vc5_driver_data *vc5 = i2c_get_clientdata(client);
1027
1028 of_clk_del_provider(client->dev.of_node);
1029
Alexey Firago9adddb02017-04-07 12:12:22 +03001030 if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL)
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001031 clk_unregister_fixed_rate(vc5->pin_xin);
1032
1033 return 0;
1034}
1035
Marek Vasut8cbdc1f2018-12-13 17:15:28 +01001036static int __maybe_unused vc5_suspend(struct device *dev)
1037{
1038 struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
1039
1040 regcache_cache_only(vc5->regmap, true);
1041 regcache_mark_dirty(vc5->regmap);
1042
1043 return 0;
1044}
1045
1046static int __maybe_unused vc5_resume(struct device *dev)
1047{
1048 struct vc5_driver_data *vc5 = dev_get_drvdata(dev);
1049 int ret;
1050
1051 regcache_cache_only(vc5->regmap, false);
1052 ret = regcache_sync(vc5->regmap);
1053 if (ret)
1054 dev_err(dev, "Failed to restore register map: %d\n", ret);
1055 return ret;
1056}
1057
Alexey Firago9adddb02017-04-07 12:12:22 +03001058static const struct vc5_chip_info idt_5p49v5923_info = {
1059 .model = IDT_VC5_5P49V5923,
1060 .clk_fod_cnt = 2,
1061 .clk_out_cnt = 3,
1062 .flags = 0,
1063};
1064
Vladimir Barinovb1911552017-07-09 20:39:57 +03001065static const struct vc5_chip_info idt_5p49v5925_info = {
1066 .model = IDT_VC5_5P49V5925,
1067 .clk_fod_cnt = 4,
1068 .clk_out_cnt = 5,
1069 .flags = 0,
1070};
1071
Alexey Firago9adddb02017-04-07 12:12:22 +03001072static const struct vc5_chip_info idt_5p49v5933_info = {
1073 .model = IDT_VC5_5P49V5933,
1074 .clk_fod_cnt = 2,
1075 .clk_out_cnt = 3,
1076 .flags = VC5_HAS_INTERNAL_XTAL,
1077};
1078
Alexey Firago1193e142017-04-07 12:12:24 +03001079static const struct vc5_chip_info idt_5p49v5935_info = {
1080 .model = IDT_VC5_5P49V5935,
1081 .clk_fod_cnt = 4,
1082 .clk_out_cnt = 5,
1083 .flags = VC5_HAS_INTERNAL_XTAL,
1084};
1085
Marek Vasutdbf6b162017-07-09 15:28:14 +02001086static const struct vc5_chip_info idt_5p49v6901_info = {
1087 .model = IDT_VC6_5P49V6901,
1088 .clk_fod_cnt = 4,
1089 .clk_out_cnt = 5,
1090 .flags = VC5_HAS_PFD_FREQ_DBL,
1091};
1092
Adam Ford2bda7482020-04-04 11:15:35 -05001093static const struct vc5_chip_info idt_5p49v6965_info = {
1094 .model = IDT_VC6_5P49V6965,
1095 .clk_fod_cnt = 4,
1096 .clk_out_cnt = 5,
1097 .flags = 0,
1098};
1099
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001100static const struct i2c_device_id vc5_id[] = {
1101 { "5p49v5923", .driver_data = IDT_VC5_5P49V5923 },
Vladimir Barinovb1911552017-07-09 20:39:57 +03001102 { "5p49v5925", .driver_data = IDT_VC5_5P49V5925 },
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001103 { "5p49v5933", .driver_data = IDT_VC5_5P49V5933 },
Alexey Firago1193e142017-04-07 12:12:24 +03001104 { "5p49v5935", .driver_data = IDT_VC5_5P49V5935 },
Marek Vasutdbf6b162017-07-09 15:28:14 +02001105 { "5p49v6901", .driver_data = IDT_VC6_5P49V6901 },
Adam Ford2bda7482020-04-04 11:15:35 -05001106 { "5p49v6965", .driver_data = IDT_VC6_5P49V6965 },
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001107 { }
1108};
1109MODULE_DEVICE_TABLE(i2c, vc5_id);
1110
1111static const struct of_device_id clk_vc5_of_match[] = {
Alexey Firago9adddb02017-04-07 12:12:22 +03001112 { .compatible = "idt,5p49v5923", .data = &idt_5p49v5923_info },
Vladimir Barinovb1911552017-07-09 20:39:57 +03001113 { .compatible = "idt,5p49v5925", .data = &idt_5p49v5925_info },
Alexey Firago9adddb02017-04-07 12:12:22 +03001114 { .compatible = "idt,5p49v5933", .data = &idt_5p49v5933_info },
Alexey Firago1193e142017-04-07 12:12:24 +03001115 { .compatible = "idt,5p49v5935", .data = &idt_5p49v5935_info },
Marek Vasutdbf6b162017-07-09 15:28:14 +02001116 { .compatible = "idt,5p49v6901", .data = &idt_5p49v6901_info },
Adam Ford2bda7482020-04-04 11:15:35 -05001117 { .compatible = "idt,5p49v6965", .data = &idt_5p49v6965_info },
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001118 { },
1119};
1120MODULE_DEVICE_TABLE(of, clk_vc5_of_match);
1121
Marek Vasut8cbdc1f2018-12-13 17:15:28 +01001122static SIMPLE_DEV_PM_OPS(vc5_pm_ops, vc5_suspend, vc5_resume);
1123
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001124static struct i2c_driver vc5_driver = {
1125 .driver = {
1126 .name = "vc5",
Marek Vasut8cbdc1f2018-12-13 17:15:28 +01001127 .pm = &vc5_pm_ops,
Marek Vasut3e1aec4e2017-01-12 02:03:24 +01001128 .of_match_table = clk_vc5_of_match,
1129 },
1130 .probe = vc5_probe,
1131 .remove = vc5_remove,
1132 .id_table = vc5_id,
1133};
1134module_i2c_driver(vc5_driver);
1135
1136MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
1137MODULE_DESCRIPTION("IDT VersaClock 5 driver");
1138MODULE_LICENSE("GPL");