Commit | Line | Data |
---|---|---|
892e0dde MV |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Driver for Renesas 9-series PCIe clock generator driver | |
4 | * | |
5 | * The following series can be supported: | |
6 | * - 9FGV/9DBV/9DMV/9FGL/9DML/9QXL/9SQ | |
7 | * Currently supported: | |
8 | * - 9FGV0241 | |
e44fdd11 | 9 | * - 9FGV0441 |
892e0dde MV |
10 | * |
11 | * Copyright (C) 2022 Marek Vasut <marex@denx.de> | |
12 | */ | |
13 | ||
14 | #include <linux/clk-provider.h> | |
15 | #include <linux/i2c.h> | |
16 | #include <linux/mod_devicetable.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/of.h> | |
19 | #include <linux/regmap.h> | |
20 | ||
21 | #define RS9_REG_OE 0x0 | |
892e0dde MV |
22 | #define RS9_REG_SS 0x1 |
23 | #define RS9_REG_SS_AMP_0V6 0x0 | |
24 | #define RS9_REG_SS_AMP_0V7 0x1 | |
25 | #define RS9_REG_SS_AMP_0V8 0x2 | |
26 | #define RS9_REG_SS_AMP_0V9 0x3 | |
27 | #define RS9_REG_SS_AMP_MASK 0x3 | |
28 | #define RS9_REG_SS_SSC_100 0 | |
29 | #define RS9_REG_SS_SSC_M025 (1 << 3) | |
30 | #define RS9_REG_SS_SSC_M050 (3 << 3) | |
31 | #define RS9_REG_SS_SSC_MASK (3 << 3) | |
32 | #define RS9_REG_SS_SSC_LOCK BIT(5) | |
33 | #define RS9_REG_SR 0x2 | |
892e0dde MV |
34 | #define RS9_REG_REF 0x3 |
35 | #define RS9_REG_REF_OE BIT(4) | |
36 | #define RS9_REG_REF_OD BIT(5) | |
37 | #define RS9_REG_REF_SR_SLOWEST 0 | |
38 | #define RS9_REG_REF_SR_SLOW (1 << 6) | |
39 | #define RS9_REG_REF_SR_FAST (2 << 6) | |
40 | #define RS9_REG_REF_SR_FASTER (3 << 6) | |
41 | #define RS9_REG_VID 0x5 | |
42 | #define RS9_REG_DID 0x6 | |
43 | #define RS9_REG_BCP 0x7 | |
44 | ||
da751726 AS |
45 | #define RS9_REG_VID_IDT 0x01 |
46 | ||
47 | #define RS9_REG_DID_TYPE_FGV (0x0 << RS9_REG_DID_TYPE_SHIFT) | |
48 | #define RS9_REG_DID_TYPE_DBV (0x1 << RS9_REG_DID_TYPE_SHIFT) | |
49 | #define RS9_REG_DID_TYPE_DMV (0x2 << RS9_REG_DID_TYPE_SHIFT) | |
50 | #define RS9_REG_DID_TYPE_SHIFT 0x6 | |
51 | ||
892e0dde MV |
52 | /* Supported Renesas 9-series models. */ |
53 | enum rs9_model { | |
54 | RENESAS_9FGV0241, | |
e44fdd11 | 55 | RENESAS_9FGV0441, |
892e0dde MV |
56 | }; |
57 | ||
58 | /* Structure to describe features of a particular 9-series model */ | |
59 | struct rs9_chip_info { | |
60 | const enum rs9_model model; | |
61 | unsigned int num_clks; | |
da751726 | 62 | u8 did; |
892e0dde MV |
63 | }; |
64 | ||
65 | struct rs9_driver_data { | |
66 | struct i2c_client *client; | |
67 | struct regmap *regmap; | |
68 | const struct rs9_chip_info *chip_info; | |
e44fdd11 | 69 | struct clk_hw *clk_dif[4]; |
892e0dde MV |
70 | u8 pll_amplitude; |
71 | u8 pll_ssc; | |
72 | u8 clk_dif_sr; | |
73 | }; | |
74 | ||
75 | /* | |
76 | * Renesas 9-series i2c regmap | |
77 | */ | |
78 | static const struct regmap_range rs9_readable_ranges[] = { | |
79 | regmap_reg_range(RS9_REG_OE, RS9_REG_REF), | |
80 | regmap_reg_range(RS9_REG_VID, RS9_REG_BCP), | |
81 | }; | |
82 | ||
83 | static const struct regmap_access_table rs9_readable_table = { | |
84 | .yes_ranges = rs9_readable_ranges, | |
85 | .n_yes_ranges = ARRAY_SIZE(rs9_readable_ranges), | |
86 | }; | |
87 | ||
88 | static const struct regmap_range rs9_writeable_ranges[] = { | |
89 | regmap_reg_range(RS9_REG_OE, RS9_REG_REF), | |
90 | regmap_reg_range(RS9_REG_BCP, RS9_REG_BCP), | |
91 | }; | |
92 | ||
93 | static const struct regmap_access_table rs9_writeable_table = { | |
94 | .yes_ranges = rs9_writeable_ranges, | |
95 | .n_yes_ranges = ARRAY_SIZE(rs9_writeable_ranges), | |
96 | }; | |
97 | ||
2ff4ba9e MV |
98 | static int rs9_regmap_i2c_write(void *context, |
99 | unsigned int reg, unsigned int val) | |
100 | { | |
101 | struct i2c_client *i2c = context; | |
102 | const u8 data[3] = { reg, 1, val }; | |
103 | const int count = ARRAY_SIZE(data); | |
104 | int ret; | |
105 | ||
106 | ret = i2c_master_send(i2c, data, count); | |
107 | if (ret == count) | |
108 | return 0; | |
109 | else if (ret < 0) | |
110 | return ret; | |
111 | else | |
112 | return -EIO; | |
113 | } | |
114 | ||
115 | static int rs9_regmap_i2c_read(void *context, | |
116 | unsigned int reg, unsigned int *val) | |
117 | { | |
118 | struct i2c_client *i2c = context; | |
119 | struct i2c_msg xfer[2]; | |
120 | u8 txdata = reg; | |
121 | u8 rxdata[2]; | |
122 | int ret; | |
123 | ||
124 | xfer[0].addr = i2c->addr; | |
125 | xfer[0].flags = 0; | |
126 | xfer[0].len = 1; | |
127 | xfer[0].buf = (void *)&txdata; | |
128 | ||
129 | xfer[1].addr = i2c->addr; | |
130 | xfer[1].flags = I2C_M_RD; | |
131 | xfer[1].len = 2; | |
132 | xfer[1].buf = (void *)rxdata; | |
133 | ||
134 | ret = i2c_transfer(i2c->adapter, xfer, 2); | |
135 | if (ret < 0) | |
136 | return ret; | |
137 | if (ret != 2) | |
138 | return -EIO; | |
139 | ||
140 | /* | |
141 | * Byte 0 is transfer length, which is always 1 due | |
142 | * to BCP register programming to 1 in rs9_probe(), | |
143 | * ignore it and use data from Byte 1. | |
144 | */ | |
145 | *val = rxdata[1]; | |
146 | return 0; | |
147 | } | |
148 | ||
892e0dde MV |
149 | static const struct regmap_config rs9_regmap_config = { |
150 | .reg_bits = 8, | |
151 | .val_bits = 8, | |
632e0473 | 152 | .cache_type = REGCACHE_FLAT, |
2ff4ba9e | 153 | .max_register = RS9_REG_BCP, |
632e0473 | 154 | .num_reg_defaults_raw = 0x8, |
892e0dde MV |
155 | .rd_table = &rs9_readable_table, |
156 | .wr_table = &rs9_writeable_table, | |
2ff4ba9e MV |
157 | .reg_write = rs9_regmap_i2c_write, |
158 | .reg_read = rs9_regmap_i2c_read, | |
892e0dde MV |
159 | }; |
160 | ||
603df193 AS |
161 | static u8 rs9_calc_dif(const struct rs9_driver_data *rs9, int idx) |
162 | { | |
163 | enum rs9_model model = rs9->chip_info->model; | |
164 | ||
165 | if (model == RENESAS_9FGV0241) | |
166 | return BIT(idx) + 1; | |
e44fdd11 AS |
167 | else if (model == RENESAS_9FGV0441) |
168 | return BIT(idx); | |
603df193 AS |
169 | |
170 | return 0; | |
171 | } | |
172 | ||
892e0dde MV |
173 | static int rs9_get_output_config(struct rs9_driver_data *rs9, int idx) |
174 | { | |
175 | struct i2c_client *client = rs9->client; | |
603df193 | 176 | u8 dif = rs9_calc_dif(rs9, idx); |
892e0dde MV |
177 | unsigned char name[5] = "DIF0"; |
178 | struct device_node *np; | |
179 | int ret; | |
180 | u32 sr; | |
181 | ||
182 | /* Set defaults */ | |
603df193 | 183 | rs9->clk_dif_sr |= dif; |
892e0dde MV |
184 | |
185 | snprintf(name, 5, "DIF%d", idx); | |
186 | np = of_get_child_by_name(client->dev.of_node, name); | |
187 | if (!np) | |
188 | return 0; | |
189 | ||
190 | /* Output clock slew rate */ | |
191 | ret = of_property_read_u32(np, "renesas,slew-rate", &sr); | |
192 | of_node_put(np); | |
193 | if (!ret) { | |
194 | if (sr == 2000000) { /* 2V/ns */ | |
603df193 | 195 | rs9->clk_dif_sr &= ~dif; |
892e0dde | 196 | } else if (sr == 3000000) { /* 3V/ns (default) */ |
603df193 | 197 | rs9->clk_dif_sr |= dif; |
892e0dde MV |
198 | } else |
199 | ret = dev_err_probe(&client->dev, -EINVAL, | |
200 | "Invalid renesas,slew-rate value\n"); | |
201 | } | |
202 | ||
203 | return ret; | |
204 | } | |
205 | ||
206 | static int rs9_get_common_config(struct rs9_driver_data *rs9) | |
207 | { | |
208 | struct i2c_client *client = rs9->client; | |
209 | struct device_node *np = client->dev.of_node; | |
210 | unsigned int amp, ssc; | |
211 | int ret; | |
212 | ||
213 | /* Set defaults */ | |
214 | rs9->pll_amplitude = RS9_REG_SS_AMP_0V7; | |
215 | rs9->pll_ssc = RS9_REG_SS_SSC_100; | |
216 | ||
217 | /* Output clock amplitude */ | |
218 | ret = of_property_read_u32(np, "renesas,out-amplitude-microvolt", | |
219 | &); | |
220 | if (!ret) { | |
221 | if (amp == 600000) /* 0.6V */ | |
222 | rs9->pll_amplitude = RS9_REG_SS_AMP_0V6; | |
223 | else if (amp == 700000) /* 0.7V (default) */ | |
224 | rs9->pll_amplitude = RS9_REG_SS_AMP_0V7; | |
225 | else if (amp == 800000) /* 0.8V */ | |
226 | rs9->pll_amplitude = RS9_REG_SS_AMP_0V8; | |
227 | else if (amp == 900000) /* 0.9V */ | |
228 | rs9->pll_amplitude = RS9_REG_SS_AMP_0V9; | |
229 | else | |
230 | return dev_err_probe(&client->dev, -EINVAL, | |
231 | "Invalid renesas,out-amplitude-microvolt value\n"); | |
232 | } | |
233 | ||
234 | /* Output clock spread spectrum */ | |
235 | ret = of_property_read_u32(np, "renesas,out-spread-spectrum", &ssc); | |
236 | if (!ret) { | |
237 | if (ssc == 100000) /* 100% ... no spread (default) */ | |
238 | rs9->pll_ssc = RS9_REG_SS_SSC_100; | |
239 | else if (ssc == 99750) /* -0.25% ... down spread */ | |
240 | rs9->pll_ssc = RS9_REG_SS_SSC_M025; | |
241 | else if (ssc == 99500) /* -0.50% ... down spread */ | |
242 | rs9->pll_ssc = RS9_REG_SS_SSC_M050; | |
243 | else | |
244 | return dev_err_probe(&client->dev, -EINVAL, | |
245 | "Invalid renesas,out-spread-spectrum value\n"); | |
246 | } | |
247 | ||
248 | return 0; | |
249 | } | |
250 | ||
251 | static void rs9_update_config(struct rs9_driver_data *rs9) | |
252 | { | |
253 | int i; | |
254 | ||
255 | /* If amplitude is non-default, update it. */ | |
256 | if (rs9->pll_amplitude != RS9_REG_SS_AMP_0V7) { | |
257 | regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_AMP_MASK, | |
258 | rs9->pll_amplitude); | |
259 | } | |
260 | ||
261 | /* If SSC is non-default, update it. */ | |
262 | if (rs9->pll_ssc != RS9_REG_SS_SSC_100) { | |
263 | regmap_update_bits(rs9->regmap, RS9_REG_SS, RS9_REG_SS_SSC_MASK, | |
264 | rs9->pll_ssc); | |
265 | } | |
266 | ||
267 | for (i = 0; i < rs9->chip_info->num_clks; i++) { | |
603df193 AS |
268 | u8 dif = rs9_calc_dif(rs9, i); |
269 | ||
270 | if (rs9->clk_dif_sr & dif) | |
892e0dde MV |
271 | continue; |
272 | ||
603df193 AS |
273 | regmap_update_bits(rs9->regmap, RS9_REG_SR, dif, |
274 | rs9->clk_dif_sr & dif); | |
892e0dde MV |
275 | } |
276 | } | |
277 | ||
278 | static struct clk_hw * | |
279 | rs9_of_clk_get(struct of_phandle_args *clkspec, void *data) | |
280 | { | |
281 | struct rs9_driver_data *rs9 = data; | |
282 | unsigned int idx = clkspec->args[0]; | |
283 | ||
284 | return rs9->clk_dif[idx]; | |
285 | } | |
286 | ||
5baa12cf | 287 | static int rs9_probe(struct i2c_client *client) |
892e0dde MV |
288 | { |
289 | unsigned char name[5] = "DIF0"; | |
290 | struct rs9_driver_data *rs9; | |
da751726 | 291 | unsigned int vid, did; |
892e0dde MV |
292 | struct clk_hw *hw; |
293 | int i, ret; | |
294 | ||
295 | rs9 = devm_kzalloc(&client->dev, sizeof(*rs9), GFP_KERNEL); | |
296 | if (!rs9) | |
297 | return -ENOMEM; | |
298 | ||
299 | i2c_set_clientdata(client, rs9); | |
300 | rs9->client = client; | |
301 | rs9->chip_info = device_get_match_data(&client->dev); | |
302 | if (!rs9->chip_info) | |
303 | return -EINVAL; | |
304 | ||
305 | /* Fetch common configuration from DT (if specified) */ | |
306 | ret = rs9_get_common_config(rs9); | |
307 | if (ret) | |
308 | return ret; | |
309 | ||
310 | /* Fetch DIFx output configuration from DT (if specified) */ | |
311 | for (i = 0; i < rs9->chip_info->num_clks; i++) { | |
312 | ret = rs9_get_output_config(rs9, i); | |
313 | if (ret) | |
314 | return ret; | |
315 | } | |
316 | ||
2ff4ba9e MV |
317 | rs9->regmap = devm_regmap_init(&client->dev, NULL, |
318 | client, &rs9_regmap_config); | |
892e0dde MV |
319 | if (IS_ERR(rs9->regmap)) |
320 | return dev_err_probe(&client->dev, PTR_ERR(rs9->regmap), | |
321 | "Failed to allocate register map\n"); | |
322 | ||
2ff4ba9e MV |
323 | /* Always read back 1 Byte via I2C */ |
324 | ret = regmap_write(rs9->regmap, RS9_REG_BCP, 1); | |
325 | if (ret < 0) | |
326 | return ret; | |
327 | ||
da751726 AS |
328 | ret = regmap_read(rs9->regmap, RS9_REG_VID, &vid); |
329 | if (ret < 0) | |
330 | return ret; | |
331 | ||
332 | ret = regmap_read(rs9->regmap, RS9_REG_DID, &did); | |
333 | if (ret < 0) | |
334 | return ret; | |
335 | ||
336 | if (vid != RS9_REG_VID_IDT || did != rs9->chip_info->did) | |
337 | return dev_err_probe(&client->dev, -ENODEV, | |
338 | "Incorrect VID/DID: %#02x, %#02x. Expected %#02x, %#02x\n", | |
339 | vid, did, RS9_REG_VID_IDT, | |
340 | rs9->chip_info->did); | |
341 | ||
892e0dde MV |
342 | /* Register clock */ |
343 | for (i = 0; i < rs9->chip_info->num_clks; i++) { | |
344 | snprintf(name, 5, "DIF%d", i); | |
345 | hw = devm_clk_hw_register_fixed_factor_index(&client->dev, name, | |
346 | 0, 0, 4, 1); | |
347 | if (IS_ERR(hw)) | |
348 | return PTR_ERR(hw); | |
349 | ||
350 | rs9->clk_dif[i] = hw; | |
351 | } | |
352 | ||
353 | ret = devm_of_clk_add_hw_provider(&client->dev, rs9_of_clk_get, rs9); | |
354 | if (!ret) | |
355 | rs9_update_config(rs9); | |
356 | ||
357 | return ret; | |
358 | } | |
359 | ||
360 | static int __maybe_unused rs9_suspend(struct device *dev) | |
361 | { | |
362 | struct rs9_driver_data *rs9 = dev_get_drvdata(dev); | |
363 | ||
364 | regcache_cache_only(rs9->regmap, true); | |
365 | regcache_mark_dirty(rs9->regmap); | |
366 | ||
367 | return 0; | |
368 | } | |
369 | ||
370 | static int __maybe_unused rs9_resume(struct device *dev) | |
371 | { | |
372 | struct rs9_driver_data *rs9 = dev_get_drvdata(dev); | |
373 | int ret; | |
374 | ||
375 | regcache_cache_only(rs9->regmap, false); | |
376 | ret = regcache_sync(rs9->regmap); | |
377 | if (ret) | |
378 | dev_err(dev, "Failed to restore register map: %d\n", ret); | |
379 | return ret; | |
380 | } | |
381 | ||
382 | static const struct rs9_chip_info renesas_9fgv0241_info = { | |
383 | .model = RENESAS_9FGV0241, | |
384 | .num_clks = 2, | |
da751726 | 385 | .did = RS9_REG_DID_TYPE_FGV | 0x02, |
892e0dde MV |
386 | }; |
387 | ||
e44fdd11 AS |
388 | static const struct rs9_chip_info renesas_9fgv0441_info = { |
389 | .model = RENESAS_9FGV0441, | |
390 | .num_clks = 4, | |
391 | .did = RS9_REG_DID_TYPE_FGV | 0x04, | |
892e0dde MV |
392 | }; |
393 | ||
394 | static const struct i2c_device_id rs9_id[] = { | |
395 | { "9fgv0241", .driver_data = RENESAS_9FGV0241 }, | |
e44fdd11 | 396 | { "9fgv0441", .driver_data = RENESAS_9FGV0441 }, |
892e0dde MV |
397 | { } |
398 | }; | |
399 | MODULE_DEVICE_TABLE(i2c, rs9_id); | |
400 | ||
401 | static const struct of_device_id clk_rs9_of_match[] = { | |
402 | { .compatible = "renesas,9fgv0241", .data = &renesas_9fgv0241_info }, | |
e44fdd11 | 403 | { .compatible = "renesas,9fgv0441", .data = &renesas_9fgv0441_info }, |
892e0dde MV |
404 | { } |
405 | }; | |
406 | MODULE_DEVICE_TABLE(of, clk_rs9_of_match); | |
407 | ||
408 | static SIMPLE_DEV_PM_OPS(rs9_pm_ops, rs9_suspend, rs9_resume); | |
409 | ||
410 | static struct i2c_driver rs9_driver = { | |
411 | .driver = { | |
412 | .name = "clk-renesas-pcie-9series", | |
413 | .pm = &rs9_pm_ops, | |
414 | .of_match_table = clk_rs9_of_match, | |
415 | }, | |
5baa12cf | 416 | .probe_new = rs9_probe, |
892e0dde MV |
417 | .id_table = rs9_id, |
418 | }; | |
419 | module_i2c_driver(rs9_driver); | |
420 | ||
421 | MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); | |
422 | MODULE_DESCRIPTION("Renesas 9-series PCIe clock generator driver"); | |
423 | MODULE_LICENSE("GPL"); |