1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Driver for Skyworks Si521xx PCIe clock generator driver
5 * The following series can be supported:
12 * Copyright (C) 2022 Marek Vasut <marex@denx.de>
15 #include <linux/bitfield.h>
16 #include <linux/bitrev.h>
17 #include <linux/clk-provider.h>
18 #include <linux/i2c.h>
19 #include <linux/mod_devicetable.h>
20 #include <linux/module.h>
22 #include <linux/regmap.h>
24 /* OE1 and OE2 register */
25 #define SI521XX_REG_OE(n) (((n) & 0x1) + 1)
26 #define SI521XX_REG_ID 0x3
27 #define SI521XX_REG_ID_PROG GENMASK(7, 4)
28 #define SI521XX_REG_ID_VENDOR GENMASK(3, 0)
29 #define SI521XX_REG_BC 0x4
30 #define SI521XX_REG_DA 0x5
31 #define SI521XX_REG_DA_AMP_SEL BIT(7)
32 #define SI521XX_REG_DA_AMP_MASK GENMASK(6, 4)
33 #define SI521XX_REG_DA_AMP_MIN 300000
34 #define SI521XX_REG_DA_AMP_DEFAULT 800000
35 #define SI521XX_REG_DA_AMP_MAX 1000000
36 #define SI521XX_REG_DA_AMP_STEP 100000
37 #define SI521XX_REG_DA_AMP(UV) \
38 FIELD_PREP(SI521XX_REG_DA_AMP_MASK, \
39 ((UV) - SI521XX_REG_DA_AMP_MIN) / SI521XX_REG_DA_AMP_STEP)
40 #define SI521XX_REG_DA_UNKNOWN BIT(3) /* Always set */
42 /* Count of populated OE bits in control register ref, 1 and 2 */
43 #define SI521XX_OE_MAP(cr1, cr2) (((cr2) << 8) | (cr1))
44 #define SI521XX_OE_MAP_GET_OE(oe, map) (((map) >> (((oe) - 1) * 8)) & 0xff)
46 #define SI521XX_DIFF_MULT 4
47 #define SI521XX_DIFF_DIV 1
49 /* Supported Skyworks Si521xx models. */
66 struct i2c_client
*client
;
67 struct regmap
*regmap
;
68 struct si_clk clk_dif
[9];
76 static const struct regmap_range si521xx_readable_ranges
[] = {
77 regmap_reg_range(SI521XX_REG_OE(0), SI521XX_REG_DA
),
80 static const struct regmap_access_table si521xx_readable_table
= {
81 .yes_ranges
= si521xx_readable_ranges
,
82 .n_yes_ranges
= ARRAY_SIZE(si521xx_readable_ranges
),
85 static const struct regmap_range si521xx_writeable_ranges
[] = {
86 regmap_reg_range(SI521XX_REG_OE(0), SI521XX_REG_OE(1)),
87 regmap_reg_range(SI521XX_REG_BC
, SI521XX_REG_DA
),
90 static const struct regmap_access_table si521xx_writeable_table
= {
91 .yes_ranges
= si521xx_writeable_ranges
,
92 .n_yes_ranges
= ARRAY_SIZE(si521xx_writeable_ranges
),
95 static int si521xx_regmap_i2c_write(void *context
, unsigned int reg
,
98 struct i2c_client
*i2c
= context
;
99 const u8 data
[2] = { reg
, val
};
100 const int count
= ARRAY_SIZE(data
);
103 ret
= i2c_master_send(i2c
, data
, count
);
112 static int si521xx_regmap_i2c_read(void *context
, unsigned int reg
,
115 struct i2c_client
*i2c
= context
;
116 struct i2c_msg xfer
[2];
121 xfer
[0].addr
= i2c
->addr
;
124 xfer
[0].buf
= (void *)&txdata
;
126 xfer
[1].addr
= i2c
->addr
;
127 xfer
[1].flags
= I2C_M_RD
;
129 xfer
[1].buf
= (void *)rxdata
;
131 ret
= i2c_transfer(i2c
->adapter
, xfer
, 2);
138 * Byte 0 is transfer length, which is always 1 due
139 * to BCP register programming to 1 in si521xx_probe(),
140 * ignore it and use data from Byte 1.
146 static const struct regmap_config si521xx_regmap_config
= {
149 .cache_type
= REGCACHE_FLAT
,
150 .max_register
= SI521XX_REG_DA
,
151 .rd_table
= &si521xx_readable_table
,
152 .wr_table
= &si521xx_writeable_table
,
153 .reg_write
= si521xx_regmap_i2c_write
,
154 .reg_read
= si521xx_regmap_i2c_read
,
157 static unsigned long si521xx_diff_recalc_rate(struct clk_hw
*hw
,
158 unsigned long parent_rate
)
160 unsigned long long rate
;
162 rate
= (unsigned long long)parent_rate
* SI521XX_DIFF_MULT
;
163 do_div(rate
, SI521XX_DIFF_DIV
);
164 return (unsigned long)rate
;
167 static long si521xx_diff_round_rate(struct clk_hw
*hw
, unsigned long rate
,
168 unsigned long *prate
)
170 unsigned long best_parent
;
172 best_parent
= (rate
/ SI521XX_DIFF_MULT
) * SI521XX_DIFF_DIV
;
173 *prate
= clk_hw_round_rate(clk_hw_get_parent(hw
), best_parent
);
175 return (*prate
/ SI521XX_DIFF_DIV
) * SI521XX_DIFF_MULT
;
178 static int si521xx_diff_set_rate(struct clk_hw
*hw
, unsigned long rate
,
179 unsigned long parent_rate
)
182 * We must report success but we can do so unconditionally because
183 * si521xx_diff_round_rate returns values that ensure this call is a
190 #define to_si521xx_clk(_hw) container_of(_hw, struct si_clk, hw)
192 static int si521xx_diff_prepare(struct clk_hw
*hw
)
194 struct si_clk
*si_clk
= to_si521xx_clk(hw
);
195 struct si521xx
*si
= si_clk
->si
;
197 regmap_set_bits(si
->regmap
, SI521XX_REG_OE(si_clk
->reg
), si_clk
->bit
);
202 static void si521xx_diff_unprepare(struct clk_hw
*hw
)
204 struct si_clk
*si_clk
= to_si521xx_clk(hw
);
205 struct si521xx
*si
= si_clk
->si
;
207 regmap_clear_bits(si
->regmap
, SI521XX_REG_OE(si_clk
->reg
), si_clk
->bit
);
210 static const struct clk_ops si521xx_diff_clk_ops
= {
211 .round_rate
= si521xx_diff_round_rate
,
212 .set_rate
= si521xx_diff_set_rate
,
213 .recalc_rate
= si521xx_diff_recalc_rate
,
214 .prepare
= si521xx_diff_prepare
,
215 .unprepare
= si521xx_diff_unprepare
,
218 static int si521xx_get_common_config(struct si521xx
*si
)
220 struct i2c_client
*client
= si
->client
;
221 struct device_node
*np
= client
->dev
.of_node
;
226 si
->pll_amplitude
= SI521XX_REG_DA_AMP(SI521XX_REG_DA_AMP_DEFAULT
);
228 /* Output clock amplitude */
229 ret
= of_property_read_u32(np
, "skyworks,out-amplitude-microvolt",
232 if (amp
< SI521XX_REG_DA_AMP_MIN
|| amp
> SI521XX_REG_DA_AMP_MAX
||
233 amp
% SI521XX_REG_DA_AMP_STEP
) {
234 return dev_err_probe(&client
->dev
, -EINVAL
,
235 "Invalid skyworks,out-amplitude-microvolt value\n");
237 si
->pll_amplitude
= SI521XX_REG_DA_AMP(amp
);
243 static void si521xx_update_config(struct si521xx
*si
)
245 /* If amplitude is non-default, update it. */
246 if (si
->pll_amplitude
== SI521XX_REG_DA_AMP(SI521XX_REG_DA_AMP_DEFAULT
))
249 regmap_update_bits(si
->regmap
, SI521XX_REG_DA
,
250 SI521XX_REG_DA_AMP_MASK
, si
->pll_amplitude
);
253 static void si521xx_diff_idx_to_reg_bit(const u16 chip_info
, const int idx
,
259 for (oe
= 1; oe
<= 2; oe
++) {
260 mask
= bitrev8(SI521XX_OE_MAP_GET_OE(oe
, chip_info
));
261 for_each_set_bit(b
, &mask
, 8) {
264 clk
->reg
= SI521XX_REG_OE(oe
);
271 static struct clk_hw
*
272 si521xx_of_clk_get(struct of_phandle_args
*clkspec
, void *data
)
274 struct si521xx
*si
= data
;
275 unsigned int idx
= clkspec
->args
[0];
277 return &si
->clk_dif
[idx
].hw
;
280 static int si521xx_probe(struct i2c_client
*client
)
282 const u16 chip_info
= (u16
)(uintptr_t)i2c_get_match_data(client
);
283 const struct clk_parent_data clk_parent_data
= { .index
= 0 };
284 const u8 data
[3] = { SI521XX_REG_BC
, 1, 1 };
285 unsigned char name
[16] = "DIFF0";
286 struct clk_init_data init
= {};
293 si
= devm_kzalloc(&client
->dev
, sizeof(*si
), GFP_KERNEL
);
297 i2c_set_clientdata(client
, si
);
300 /* Fetch common configuration from DT (if specified) */
301 ret
= si521xx_get_common_config(si
);
305 si
->regmap
= devm_regmap_init(&client
->dev
, NULL
, client
,
306 &si521xx_regmap_config
);
307 if (IS_ERR(si
->regmap
))
308 return dev_err_probe(&client
->dev
, PTR_ERR(si
->regmap
),
309 "Failed to allocate register map\n");
311 /* Always read back 1 Byte via I2C */
312 ret
= i2c_master_send(client
, data
, ARRAY_SIZE(data
));
317 for (i
= 0; i
< hweight16(chip_info
); i
++) {
318 memset(&init
, 0, sizeof(init
));
319 snprintf(name
, sizeof(name
), "DIFF%d", i
);
321 init
.ops
= &si521xx_diff_clk_ops
;
322 init
.parent_data
= &clk_parent_data
;
323 init
.num_parents
= 1;
324 init
.flags
= CLK_SET_RATE_PARENT
;
326 si
->clk_dif
[i
].hw
.init
= &init
;
327 si
->clk_dif
[i
].si
= si
;
329 si521xx_diff_idx_to_reg_bit(chip_info
, i
, &si
->clk_dif
[i
]);
331 ret
= devm_clk_hw_register(&client
->dev
, &si
->clk_dif
[i
].hw
);
336 ret
= devm_of_clk_add_hw_provider(&client
->dev
, si521xx_of_clk_get
, si
);
338 si521xx_update_config(si
);
343 static int __maybe_unused
si521xx_suspend(struct device
*dev
)
345 struct si521xx
*si
= dev_get_drvdata(dev
);
347 regcache_cache_only(si
->regmap
, true);
348 regcache_mark_dirty(si
->regmap
);
353 static int __maybe_unused
si521xx_resume(struct device
*dev
)
355 struct si521xx
*si
= dev_get_drvdata(dev
);
358 regcache_cache_only(si
->regmap
, false);
359 ret
= regcache_sync(si
->regmap
);
361 dev_err(dev
, "Failed to restore register map: %d\n", ret
);
365 static const struct i2c_device_id si521xx_id
[] = {
366 { "si52144", .driver_data
= SI521XX_OE_MAP(0x5, 0xc0) },
367 { "si52146", .driver_data
= SI521XX_OE_MAP(0x15, 0xe0) },
368 { "si52147", .driver_data
= SI521XX_OE_MAP(0x17, 0xf8) },
371 MODULE_DEVICE_TABLE(i2c
, si521xx_id
);
373 static const struct of_device_id clk_si521xx_of_match
[] = {
374 { .compatible
= "skyworks,si52144", .data
= (void *)SI521XX_OE_MAP(0x5, 0xc0) },
375 { .compatible
= "skyworks,si52146", .data
= (void *)SI521XX_OE_MAP(0x15, 0xe0) },
376 { .compatible
= "skyworks,si52147", .data
= (void *)SI521XX_OE_MAP(0x15, 0xf8) },
379 MODULE_DEVICE_TABLE(of
, clk_si521xx_of_match
);
381 static SIMPLE_DEV_PM_OPS(si521xx_pm_ops
, si521xx_suspend
, si521xx_resume
);
383 static struct i2c_driver si521xx_driver
= {
385 .name
= "clk-si521xx",
386 .pm
= &si521xx_pm_ops
,
387 .of_match_table
= clk_si521xx_of_match
,
389 .probe
= si521xx_probe
,
390 .id_table
= si521xx_id
,
392 module_i2c_driver(si521xx_driver
);
394 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
395 MODULE_DESCRIPTION("Skyworks Si521xx PCIe clock generator driver");
396 MODULE_LICENSE("GPL");