]>
Commit | Line | Data |
---|---|---|
6a1beee2 AL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // FAN53555 Fairchild Digitally Programmable TinyBuck Regulator Driver. | |
4 | // | |
5 | // Supported Part Numbers: | |
6 | // FAN53555UC00X/01X/03X/04X/05X | |
7 | // | |
8 | // Copyright (c) 2012 Marvell Technology Ltd. | |
9 | // Yunfan Zhang <yfzhang@marvell.com> | |
10 | ||
49d8c599 YZ |
11 | #include <linux/module.h> |
12 | #include <linux/param.h> | |
13 | #include <linux/err.h> | |
14 | #include <linux/platform_device.h> | |
15 | #include <linux/regulator/driver.h> | |
16 | #include <linux/regulator/machine.h> | |
91f23d8f HS |
17 | #include <linux/regulator/of_regulator.h> |
18 | #include <linux/of_device.h> | |
49d8c599 YZ |
19 | #include <linux/i2c.h> |
20 | #include <linux/slab.h> | |
21 | #include <linux/regmap.h> | |
22 | #include <linux/regulator/fan53555.h> | |
23 | ||
24 | /* Voltage setting */ | |
25 | #define FAN53555_VSEL0 0x00 | |
26 | #define FAN53555_VSEL1 0x01 | |
914df8fa JC |
27 | |
28 | #define TCS4525_VSEL0 0x11 | |
29 | #define TCS4525_VSEL1 0x10 | |
30 | #define TCS4525_TIME 0x13 | |
31 | #define TCS4525_COMMAND 0x14 | |
32 | ||
49d8c599 YZ |
33 | /* Control register */ |
34 | #define FAN53555_CONTROL 0x02 | |
35 | /* IC Type */ | |
36 | #define FAN53555_ID1 0x03 | |
37 | /* IC mask version */ | |
38 | #define FAN53555_ID2 0x04 | |
39 | /* Monitor register */ | |
40 | #define FAN53555_MONITOR 0x05 | |
41 | ||
42 | /* VSEL bit definitions */ | |
43 | #define VSEL_BUCK_EN (1 << 7) | |
44 | #define VSEL_MODE (1 << 6) | |
49d8c599 YZ |
45 | /* Chip ID and Verison */ |
46 | #define DIE_ID 0x0F /* ID1 */ | |
47 | #define DIE_REV 0x0F /* ID2 */ | |
48 | /* Control bit definitions */ | |
49 | #define CTL_OUTPUT_DISCHG (1 << 7) | |
50 | #define CTL_SLEW_MASK (0x7 << 4) | |
51 | #define CTL_SLEW_SHIFT 4 | |
52 | #define CTL_RESET (1 << 2) | |
f2a9eb97 BA |
53 | #define CTL_MODE_VSEL0_MODE BIT(0) |
54 | #define CTL_MODE_VSEL1_MODE BIT(1) | |
49d8c599 YZ |
55 | |
56 | #define FAN53555_NVOLTAGES 64 /* Numbers of voltages */ | |
f2a9eb97 | 57 | #define FAN53526_NVOLTAGES 128 |
914df8fa | 58 | |
914df8fa JC |
59 | #define TCS_VSEL0_MODE (1 << 7) |
60 | #define TCS_VSEL1_MODE (1 << 6) | |
61 | ||
62 | #define TCS_SLEW_SHIFT 3 | |
63 | #define TCS_SLEW_MASK (0x3 < 3) | |
49d8c599 | 64 | |
ee30928a | 65 | enum fan53555_vendor { |
f2a9eb97 BA |
66 | FAN53526_VENDOR_FAIRCHILD = 0, |
67 | FAN53555_VENDOR_FAIRCHILD, | |
ee30928a | 68 | FAN53555_VENDOR_SILERGY, |
b3cc8ec0 | 69 | FAN53526_VENDOR_TCS, |
ee30928a HS |
70 | }; |
71 | ||
f2a9eb97 BA |
72 | enum { |
73 | FAN53526_CHIP_ID_01 = 1, | |
74 | }; | |
75 | ||
76 | enum { | |
77 | FAN53526_CHIP_REV_08 = 8, | |
78 | }; | |
79 | ||
49d8c599 YZ |
80 | /* IC Type */ |
81 | enum { | |
82 | FAN53555_CHIP_ID_00 = 0, | |
83 | FAN53555_CHIP_ID_01, | |
84 | FAN53555_CHIP_ID_02, | |
85 | FAN53555_CHIP_ID_03, | |
86 | FAN53555_CHIP_ID_04, | |
87 | FAN53555_CHIP_ID_05, | |
5e39cf49 | 88 | FAN53555_CHIP_ID_08 = 8, |
49d8c599 YZ |
89 | }; |
90 | ||
f9028dcd PG |
91 | enum { |
92 | TCS4525_CHIP_ID_12 = 12, | |
93 | }; | |
94 | ||
5eee5ece RH |
95 | enum { |
96 | TCS4526_CHIP_ID_00 = 0, | |
97 | }; | |
98 | ||
e57cbb70 WE |
99 | /* IC mask revision */ |
100 | enum { | |
101 | FAN53555_CHIP_REV_00 = 0x3, | |
102 | FAN53555_CHIP_REV_13 = 0xf, | |
103 | }; | |
104 | ||
ee30928a HS |
105 | enum { |
106 | SILERGY_SYR82X = 8, | |
5365e3df | 107 | SILERGY_SYR83X = 9, |
ee30928a HS |
108 | }; |
109 | ||
49d8c599 | 110 | struct fan53555_device_info { |
ee30928a | 111 | enum fan53555_vendor vendor; |
49d8c599 YZ |
112 | struct device *dev; |
113 | struct regulator_desc desc; | |
49d8c599 YZ |
114 | struct regulator_init_data *regulator; |
115 | /* IC Type and Rev */ | |
116 | int chip_id; | |
117 | int chip_rev; | |
118 | /* Voltage setting register */ | |
119 | unsigned int vol_reg; | |
120 | unsigned int sleep_reg; | |
121 | /* Voltage range and step(linear) */ | |
122 | unsigned int vsel_min; | |
49d8c599 | 123 | unsigned int vsel_step; |
f2a9eb97 | 124 | unsigned int vsel_count; |
f2a9eb97 BA |
125 | /* Mode */ |
126 | unsigned int mode_reg; | |
127 | unsigned int mode_mask; | |
49d8c599 YZ |
128 | /* Sleep voltage cache */ |
129 | unsigned int sleep_vol_cache; | |
914df8fa JC |
130 | /* Slew rate */ |
131 | unsigned int slew_reg; | |
132 | unsigned int slew_mask; | |
b61ac767 AL |
133 | const unsigned int *ramp_delay_table; |
134 | unsigned int n_ramp_values; | |
914df8fa | 135 | unsigned int slew_rate; |
49d8c599 YZ |
136 | }; |
137 | ||
138 | static int fan53555_set_suspend_voltage(struct regulator_dev *rdev, int uV) | |
139 | { | |
140 | struct fan53555_device_info *di = rdev_get_drvdata(rdev); | |
141 | int ret; | |
142 | ||
143 | if (di->sleep_vol_cache == uV) | |
144 | return 0; | |
145 | ret = regulator_map_voltage_linear(rdev, uV, uV); | |
146 | if (ret < 0) | |
145fe1e1 | 147 | return ret; |
a69929c7 | 148 | ret = regmap_update_bits(rdev->regmap, di->sleep_reg, |
f2a9eb97 | 149 | di->desc.vsel_mask, ret); |
49d8c599 | 150 | if (ret < 0) |
145fe1e1 | 151 | return ret; |
49d8c599 YZ |
152 | /* Cache the sleep voltage setting. |
153 | * Might not be the real voltage which is rounded */ | |
154 | di->sleep_vol_cache = uV; | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
ab7cad33 | 159 | static int fan53555_set_suspend_enable(struct regulator_dev *rdev) |
160 | { | |
161 | struct fan53555_device_info *di = rdev_get_drvdata(rdev); | |
162 | ||
a69929c7 | 163 | return regmap_update_bits(rdev->regmap, di->sleep_reg, |
ab7cad33 | 164 | VSEL_BUCK_EN, VSEL_BUCK_EN); |
165 | } | |
166 | ||
167 | static int fan53555_set_suspend_disable(struct regulator_dev *rdev) | |
168 | { | |
169 | struct fan53555_device_info *di = rdev_get_drvdata(rdev); | |
170 | ||
a69929c7 | 171 | return regmap_update_bits(rdev->regmap, di->sleep_reg, |
ab7cad33 | 172 | VSEL_BUCK_EN, 0); |
173 | } | |
174 | ||
49d8c599 YZ |
175 | static int fan53555_set_mode(struct regulator_dev *rdev, unsigned int mode) |
176 | { | |
177 | struct fan53555_device_info *di = rdev_get_drvdata(rdev); | |
178 | ||
179 | switch (mode) { | |
180 | case REGULATOR_MODE_FAST: | |
a69929c7 | 181 | regmap_update_bits(rdev->regmap, di->mode_reg, |
f2a9eb97 | 182 | di->mode_mask, di->mode_mask); |
49d8c599 YZ |
183 | break; |
184 | case REGULATOR_MODE_NORMAL: | |
a69929c7 | 185 | regmap_update_bits(rdev->regmap, di->vol_reg, di->mode_mask, 0); |
49d8c599 YZ |
186 | break; |
187 | default: | |
188 | return -EINVAL; | |
189 | } | |
190 | return 0; | |
191 | } | |
192 | ||
193 | static unsigned int fan53555_get_mode(struct regulator_dev *rdev) | |
194 | { | |
195 | struct fan53555_device_info *di = rdev_get_drvdata(rdev); | |
196 | unsigned int val; | |
197 | int ret = 0; | |
198 | ||
a69929c7 | 199 | ret = regmap_read(rdev->regmap, di->mode_reg, &val); |
49d8c599 YZ |
200 | if (ret < 0) |
201 | return ret; | |
f2a9eb97 | 202 | if (val & di->mode_mask) |
49d8c599 YZ |
203 | return REGULATOR_MODE_FAST; |
204 | else | |
205 | return REGULATOR_MODE_NORMAL; | |
206 | } | |
207 | ||
b61ac767 | 208 | static const unsigned int slew_rates[] = { |
dd7e71fb HS |
209 | 64000, |
210 | 32000, | |
211 | 16000, | |
212 | 8000, | |
213 | 4000, | |
214 | 2000, | |
215 | 1000, | |
216 | 500, | |
217 | }; | |
218 | ||
b61ac767 | 219 | static const unsigned int tcs_slew_rates[] = { |
914df8fa JC |
220 | 18700, |
221 | 9300, | |
222 | 4600, | |
223 | 2300, | |
224 | }; | |
225 | ||
71880ab2 | 226 | static const struct regulator_ops fan53555_regulator_ops = { |
49d8c599 YZ |
227 | .set_voltage_sel = regulator_set_voltage_sel_regmap, |
228 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
fda87a42 | 229 | .set_voltage_time_sel = regulator_set_voltage_time_sel, |
49d8c599 YZ |
230 | .map_voltage = regulator_map_voltage_linear, |
231 | .list_voltage = regulator_list_voltage_linear, | |
232 | .set_suspend_voltage = fan53555_set_suspend_voltage, | |
233 | .enable = regulator_enable_regmap, | |
234 | .disable = regulator_disable_regmap, | |
235 | .is_enabled = regulator_is_enabled_regmap, | |
236 | .set_mode = fan53555_set_mode, | |
237 | .get_mode = fan53555_get_mode, | |
b61ac767 | 238 | .set_ramp_delay = regulator_set_ramp_delay_regmap, |
ab7cad33 | 239 | .set_suspend_enable = fan53555_set_suspend_enable, |
240 | .set_suspend_disable = fan53555_set_suspend_disable, | |
49d8c599 YZ |
241 | }; |
242 | ||
f2a9eb97 BA |
243 | static int fan53526_voltages_setup_fairchild(struct fan53555_device_info *di) |
244 | { | |
245 | /* Init voltage range and step */ | |
246 | switch (di->chip_id) { | |
247 | case FAN53526_CHIP_ID_01: | |
248 | switch (di->chip_rev) { | |
249 | case FAN53526_CHIP_REV_08: | |
250 | di->vsel_min = 600000; | |
251 | di->vsel_step = 6250; | |
252 | break; | |
253 | default: | |
254 | dev_err(di->dev, | |
255 | "Chip ID %d with rev %d not supported!\n", | |
256 | di->chip_id, di->chip_rev); | |
257 | return -EINVAL; | |
258 | } | |
259 | break; | |
260 | default: | |
261 | dev_err(di->dev, | |
262 | "Chip ID %d not supported!\n", di->chip_id); | |
263 | return -EINVAL; | |
264 | } | |
265 | ||
30b38b80 AL |
266 | di->slew_reg = FAN53555_CONTROL; |
267 | di->slew_mask = CTL_SLEW_MASK; | |
b61ac767 AL |
268 | di->ramp_delay_table = slew_rates; |
269 | di->n_ramp_values = ARRAY_SIZE(slew_rates); | |
f2a9eb97 BA |
270 | di->vsel_count = FAN53526_NVOLTAGES; |
271 | ||
272 | return 0; | |
273 | } | |
274 | ||
ee30928a HS |
275 | static int fan53555_voltages_setup_fairchild(struct fan53555_device_info *di) |
276 | { | |
277 | /* Init voltage range and step */ | |
278 | switch (di->chip_id) { | |
279 | case FAN53555_CHIP_ID_00: | |
e57cbb70 WE |
280 | switch (di->chip_rev) { |
281 | case FAN53555_CHIP_REV_00: | |
282 | di->vsel_min = 600000; | |
283 | di->vsel_step = 10000; | |
284 | break; | |
285 | case FAN53555_CHIP_REV_13: | |
286 | di->vsel_min = 800000; | |
287 | di->vsel_step = 10000; | |
288 | break; | |
289 | default: | |
290 | dev_err(di->dev, | |
291 | "Chip ID %d with rev %d not supported!\n", | |
292 | di->chip_id, di->chip_rev); | |
293 | return -EINVAL; | |
294 | } | |
295 | break; | |
ee30928a HS |
296 | case FAN53555_CHIP_ID_01: |
297 | case FAN53555_CHIP_ID_03: | |
298 | case FAN53555_CHIP_ID_05: | |
5e39cf49 | 299 | case FAN53555_CHIP_ID_08: |
ee30928a HS |
300 | di->vsel_min = 600000; |
301 | di->vsel_step = 10000; | |
302 | break; | |
303 | case FAN53555_CHIP_ID_04: | |
304 | di->vsel_min = 603000; | |
305 | di->vsel_step = 12826; | |
306 | break; | |
307 | default: | |
308 | dev_err(di->dev, | |
309 | "Chip ID %d not supported!\n", di->chip_id); | |
310 | return -EINVAL; | |
311 | } | |
914df8fa JC |
312 | di->slew_reg = FAN53555_CONTROL; |
313 | di->slew_mask = CTL_SLEW_MASK; | |
b61ac767 AL |
314 | di->ramp_delay_table = slew_rates; |
315 | di->n_ramp_values = ARRAY_SIZE(slew_rates); | |
f2a9eb97 BA |
316 | di->vsel_count = FAN53555_NVOLTAGES; |
317 | ||
ee30928a HS |
318 | return 0; |
319 | } | |
320 | ||
321 | static int fan53555_voltages_setup_silergy(struct fan53555_device_info *di) | |
322 | { | |
323 | /* Init voltage range and step */ | |
324 | switch (di->chip_id) { | |
325 | case SILERGY_SYR82X: | |
5365e3df | 326 | case SILERGY_SYR83X: |
ee30928a HS |
327 | di->vsel_min = 712500; |
328 | di->vsel_step = 12500; | |
329 | break; | |
330 | default: | |
331 | dev_err(di->dev, | |
332 | "Chip ID %d not supported!\n", di->chip_id); | |
333 | return -EINVAL; | |
334 | } | |
914df8fa | 335 | di->slew_reg = FAN53555_CONTROL; |
914df8fa | 336 | di->slew_mask = CTL_SLEW_MASK; |
b61ac767 AL |
337 | di->ramp_delay_table = slew_rates; |
338 | di->n_ramp_values = ARRAY_SIZE(slew_rates); | |
f2a9eb97 BA |
339 | di->vsel_count = FAN53555_NVOLTAGES; |
340 | ||
ee30928a HS |
341 | return 0; |
342 | } | |
343 | ||
b3cc8ec0 | 344 | static int fan53526_voltages_setup_tcs(struct fan53555_device_info *di) |
914df8fa | 345 | { |
f9028dcd PG |
346 | switch (di->chip_id) { |
347 | case TCS4525_CHIP_ID_12: | |
5eee5ece | 348 | case TCS4526_CHIP_ID_00: |
f9028dcd PG |
349 | di->slew_reg = TCS4525_TIME; |
350 | di->slew_mask = TCS_SLEW_MASK; | |
b61ac767 AL |
351 | di->ramp_delay_table = tcs_slew_rates; |
352 | di->n_ramp_values = ARRAY_SIZE(tcs_slew_rates); | |
914df8fa | 353 | |
f9028dcd PG |
354 | /* Init voltage range and step */ |
355 | di->vsel_min = 600000; | |
356 | di->vsel_step = 6250; | |
357 | di->vsel_count = FAN53526_NVOLTAGES; | |
358 | break; | |
359 | default: | |
360 | dev_err(di->dev, "Chip ID %d not supported!\n", di->chip_id); | |
361 | return -EINVAL; | |
362 | } | |
914df8fa JC |
363 | |
364 | return 0; | |
365 | } | |
366 | ||
49d8c599 YZ |
367 | /* For 00,01,03,05 options: |
368 | * VOUT = 0.60V + NSELx * 10mV, from 0.60 to 1.23V. | |
369 | * For 04 option: | |
370 | * VOUT = 0.603V + NSELx * 12.826mV, from 0.603 to 1.411V. | |
371 | * */ | |
372 | static int fan53555_device_setup(struct fan53555_device_info *di, | |
373 | struct fan53555_platform_data *pdata) | |
374 | { | |
ee30928a HS |
375 | int ret = 0; |
376 | ||
49d8c599 | 377 | /* Setup voltage control register */ |
914df8fa JC |
378 | switch (di->vendor) { |
379 | case FAN53526_VENDOR_FAIRCHILD: | |
380 | case FAN53555_VENDOR_FAIRCHILD: | |
381 | case FAN53555_VENDOR_SILERGY: | |
382 | switch (pdata->sleep_vsel_id) { | |
383 | case FAN53555_VSEL_ID_0: | |
384 | di->sleep_reg = FAN53555_VSEL0; | |
385 | di->vol_reg = FAN53555_VSEL1; | |
386 | break; | |
387 | case FAN53555_VSEL_ID_1: | |
388 | di->sleep_reg = FAN53555_VSEL1; | |
389 | di->vol_reg = FAN53555_VSEL0; | |
390 | break; | |
391 | default: | |
392 | dev_err(di->dev, "Invalid VSEL ID!\n"); | |
393 | return -EINVAL; | |
394 | } | |
49d8c599 | 395 | break; |
b3cc8ec0 | 396 | case FAN53526_VENDOR_TCS: |
914df8fa JC |
397 | switch (pdata->sleep_vsel_id) { |
398 | case FAN53555_VSEL_ID_0: | |
399 | di->sleep_reg = TCS4525_VSEL0; | |
400 | di->vol_reg = TCS4525_VSEL1; | |
401 | break; | |
402 | case FAN53555_VSEL_ID_1: | |
403 | di->sleep_reg = TCS4525_VSEL1; | |
404 | di->vol_reg = TCS4525_VSEL0; | |
405 | break; | |
406 | default: | |
407 | dev_err(di->dev, "Invalid VSEL ID!\n"); | |
408 | return -EINVAL; | |
409 | } | |
49d8c599 YZ |
410 | break; |
411 | default: | |
914df8fa | 412 | dev_err(di->dev, "vendor %d not supported!\n", di->vendor); |
49d8c599 YZ |
413 | return -EINVAL; |
414 | } | |
ee30928a | 415 | |
f2a9eb97 BA |
416 | /* Setup mode control register */ |
417 | switch (di->vendor) { | |
418 | case FAN53526_VENDOR_FAIRCHILD: | |
419 | di->mode_reg = FAN53555_CONTROL; | |
420 | ||
421 | switch (pdata->sleep_vsel_id) { | |
422 | case FAN53555_VSEL_ID_0: | |
423 | di->mode_mask = CTL_MODE_VSEL1_MODE; | |
424 | break; | |
425 | case FAN53555_VSEL_ID_1: | |
426 | di->mode_mask = CTL_MODE_VSEL0_MODE; | |
427 | break; | |
428 | } | |
429 | break; | |
430 | case FAN53555_VENDOR_FAIRCHILD: | |
431 | case FAN53555_VENDOR_SILERGY: | |
432 | di->mode_reg = di->vol_reg; | |
433 | di->mode_mask = VSEL_MODE; | |
434 | break; | |
b3cc8ec0 | 435 | case FAN53526_VENDOR_TCS: |
914df8fa JC |
436 | di->mode_reg = TCS4525_COMMAND; |
437 | ||
438 | switch (pdata->sleep_vsel_id) { | |
439 | case FAN53555_VSEL_ID_0: | |
440 | di->mode_mask = TCS_VSEL1_MODE; | |
441 | break; | |
442 | case FAN53555_VSEL_ID_1: | |
443 | di->mode_mask = TCS_VSEL0_MODE; | |
444 | break; | |
445 | } | |
446 | break; | |
f2a9eb97 BA |
447 | default: |
448 | dev_err(di->dev, "vendor %d not supported!\n", di->vendor); | |
449 | return -EINVAL; | |
450 | } | |
451 | ||
452 | /* Setup voltage range */ | |
ee30928a | 453 | switch (di->vendor) { |
f2a9eb97 BA |
454 | case FAN53526_VENDOR_FAIRCHILD: |
455 | ret = fan53526_voltages_setup_fairchild(di); | |
456 | break; | |
ee30928a HS |
457 | case FAN53555_VENDOR_FAIRCHILD: |
458 | ret = fan53555_voltages_setup_fairchild(di); | |
49d8c599 | 459 | break; |
ee30928a HS |
460 | case FAN53555_VENDOR_SILERGY: |
461 | ret = fan53555_voltages_setup_silergy(di); | |
49d8c599 | 462 | break; |
b3cc8ec0 PG |
463 | case FAN53526_VENDOR_TCS: |
464 | ret = fan53526_voltages_setup_tcs(di); | |
914df8fa | 465 | break; |
49d8c599 | 466 | default: |
fe230531 | 467 | dev_err(di->dev, "vendor %d not supported!\n", di->vendor); |
49d8c599 YZ |
468 | return -EINVAL; |
469 | } | |
dd7e71fb | 470 | |
ee30928a | 471 | return ret; |
49d8c599 YZ |
472 | } |
473 | ||
474 | static int fan53555_regulator_register(struct fan53555_device_info *di, | |
475 | struct regulator_config *config) | |
476 | { | |
477 | struct regulator_desc *rdesc = &di->desc; | |
a69929c7 | 478 | struct regulator_dev *rdev; |
49d8c599 YZ |
479 | |
480 | rdesc->name = "fan53555-reg"; | |
3415d601 | 481 | rdesc->supply_name = "vin"; |
49d8c599 YZ |
482 | rdesc->ops = &fan53555_regulator_ops; |
483 | rdesc->type = REGULATOR_VOLTAGE; | |
f2a9eb97 | 484 | rdesc->n_voltages = di->vsel_count; |
49d8c599 YZ |
485 | rdesc->enable_reg = di->vol_reg; |
486 | rdesc->enable_mask = VSEL_BUCK_EN; | |
487 | rdesc->min_uV = di->vsel_min; | |
488 | rdesc->uV_step = di->vsel_step; | |
489 | rdesc->vsel_reg = di->vol_reg; | |
f2a9eb97 | 490 | rdesc->vsel_mask = di->vsel_count - 1; |
b61ac767 AL |
491 | rdesc->ramp_reg = di->slew_reg; |
492 | rdesc->ramp_mask = di->slew_mask; | |
493 | rdesc->ramp_delay_table = di->ramp_delay_table; | |
494 | rdesc->n_ramp_values = di->n_ramp_values; | |
49d8c599 YZ |
495 | rdesc->owner = THIS_MODULE; |
496 | ||
a69929c7 AL |
497 | rdev = devm_regulator_register(di->dev, &di->desc, config); |
498 | return PTR_ERR_OR_ZERO(rdev); | |
49d8c599 YZ |
499 | } |
500 | ||
121b567d | 501 | static const struct regmap_config fan53555_regmap_config = { |
49d8c599 YZ |
502 | .reg_bits = 8, |
503 | .val_bits = 8, | |
504 | }; | |
505 | ||
91f23d8f | 506 | static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev, |
072e78b1 JMC |
507 | struct device_node *np, |
508 | const struct regulator_desc *desc) | |
91f23d8f HS |
509 | { |
510 | struct fan53555_platform_data *pdata; | |
511 | int ret; | |
512 | u32 tmp; | |
513 | ||
514 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); | |
515 | if (!pdata) | |
516 | return NULL; | |
517 | ||
072e78b1 | 518 | pdata->regulator = of_get_regulator_init_data(dev, np, desc); |
91f23d8f HS |
519 | |
520 | ret = of_property_read_u32(np, "fcs,suspend-voltage-selector", | |
521 | &tmp); | |
522 | if (!ret) | |
523 | pdata->sleep_vsel_id = tmp; | |
524 | ||
525 | return pdata; | |
526 | } | |
527 | ||
5e97d7e8 | 528 | static const struct of_device_id __maybe_unused fan53555_dt_ids[] = { |
91f23d8f | 529 | { |
f2a9eb97 BA |
530 | .compatible = "fcs,fan53526", |
531 | .data = (void *)FAN53526_VENDOR_FAIRCHILD, | |
532 | }, { | |
91f23d8f | 533 | .compatible = "fcs,fan53555", |
ee30928a HS |
534 | .data = (void *)FAN53555_VENDOR_FAIRCHILD |
535 | }, { | |
536 | .compatible = "silergy,syr827", | |
537 | .data = (void *)FAN53555_VENDOR_SILERGY, | |
538 | }, { | |
539 | .compatible = "silergy,syr828", | |
540 | .data = (void *)FAN53555_VENDOR_SILERGY, | |
914df8fa JC |
541 | }, { |
542 | .compatible = "tcs,tcs4525", | |
b3cc8ec0 | 543 | .data = (void *)FAN53526_VENDOR_TCS |
5eee5ece RH |
544 | }, { |
545 | .compatible = "tcs,tcs4526", | |
546 | .data = (void *)FAN53526_VENDOR_TCS | |
91f23d8f HS |
547 | }, |
548 | { } | |
549 | }; | |
550 | MODULE_DEVICE_TABLE(of, fan53555_dt_ids); | |
551 | ||
a5023574 | 552 | static int fan53555_regulator_probe(struct i2c_client *client, |
49d8c599 YZ |
553 | const struct i2c_device_id *id) |
554 | { | |
91f23d8f | 555 | struct device_node *np = client->dev.of_node; |
49d8c599 YZ |
556 | struct fan53555_device_info *di; |
557 | struct fan53555_platform_data *pdata; | |
558 | struct regulator_config config = { }; | |
a69929c7 | 559 | struct regmap *regmap; |
49d8c599 YZ |
560 | unsigned int val; |
561 | int ret; | |
562 | ||
072e78b1 JMC |
563 | di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info), |
564 | GFP_KERNEL); | |
565 | if (!di) | |
566 | return -ENOMEM; | |
567 | ||
dff91d0b | 568 | pdata = dev_get_platdata(&client->dev); |
91f23d8f | 569 | if (!pdata) |
072e78b1 | 570 | pdata = fan53555_parse_dt(&client->dev, np, &di->desc); |
91f23d8f | 571 | |
49d8c599 YZ |
572 | if (!pdata || !pdata->regulator) { |
573 | dev_err(&client->dev, "Platform data not found!\n"); | |
574 | return -ENODEV; | |
575 | } | |
576 | ||
e13426bf | 577 | di->regulator = pdata->regulator; |
ee30928a | 578 | if (client->dev.of_node) { |
d110e3e9 JZ |
579 | di->vendor = |
580 | (unsigned long)of_device_get_match_data(&client->dev); | |
ee30928a | 581 | } else { |
91f23d8f HS |
582 | /* if no ramp constraint set, get the pdata ramp_delay */ |
583 | if (!di->regulator->constraints.ramp_delay) { | |
87919e0c AL |
584 | if (pdata->slew_rate >= ARRAY_SIZE(slew_rates)) { |
585 | dev_err(&client->dev, "Invalid slew_rate\n"); | |
586 | return -EINVAL; | |
587 | } | |
dd7e71fb | 588 | |
91f23d8f | 589 | di->regulator->constraints.ramp_delay |
87919e0c | 590 | = slew_rates[pdata->slew_rate]; |
91f23d8f | 591 | } |
ee30928a HS |
592 | |
593 | di->vendor = id->driver_data; | |
dd7e71fb HS |
594 | } |
595 | ||
a69929c7 AL |
596 | regmap = devm_regmap_init_i2c(client, &fan53555_regmap_config); |
597 | if (IS_ERR(regmap)) { | |
49d8c599 | 598 | dev_err(&client->dev, "Failed to allocate regmap!\n"); |
a69929c7 | 599 | return PTR_ERR(regmap); |
49d8c599 YZ |
600 | } |
601 | di->dev = &client->dev; | |
49d8c599 YZ |
602 | i2c_set_clientdata(client, di); |
603 | /* Get chip ID */ | |
a69929c7 | 604 | ret = regmap_read(regmap, FAN53555_ID1, &val); |
49d8c599 YZ |
605 | if (ret < 0) { |
606 | dev_err(&client->dev, "Failed to get chip ID!\n"); | |
145fe1e1 | 607 | return ret; |
49d8c599 YZ |
608 | } |
609 | di->chip_id = val & DIE_ID; | |
610 | /* Get chip revision */ | |
a69929c7 | 611 | ret = regmap_read(regmap, FAN53555_ID2, &val); |
49d8c599 YZ |
612 | if (ret < 0) { |
613 | dev_err(&client->dev, "Failed to get chip Rev!\n"); | |
145fe1e1 | 614 | return ret; |
49d8c599 YZ |
615 | } |
616 | di->chip_rev = val & DIE_REV; | |
617 | dev_info(&client->dev, "FAN53555 Option[%d] Rev[%d] Detected!\n", | |
618 | di->chip_id, di->chip_rev); | |
619 | /* Device init */ | |
620 | ret = fan53555_device_setup(di, pdata); | |
621 | if (ret < 0) { | |
622 | dev_err(&client->dev, "Failed to setup device!\n"); | |
623 | return ret; | |
624 | } | |
625 | /* Register regulator */ | |
626 | config.dev = di->dev; | |
627 | config.init_data = di->regulator; | |
a69929c7 | 628 | config.regmap = regmap; |
49d8c599 | 629 | config.driver_data = di; |
91f23d8f HS |
630 | config.of_node = np; |
631 | ||
49d8c599 YZ |
632 | ret = fan53555_regulator_register(di, &config); |
633 | if (ret < 0) | |
634 | dev_err(&client->dev, "Failed to register regulator!\n"); | |
635 | return ret; | |
636 | ||
637 | } | |
638 | ||
49d8c599 | 639 | static const struct i2c_device_id fan53555_id[] = { |
ee30928a | 640 | { |
f2a9eb97 BA |
641 | .name = "fan53526", |
642 | .driver_data = FAN53526_VENDOR_FAIRCHILD | |
643 | }, { | |
ee30928a HS |
644 | .name = "fan53555", |
645 | .driver_data = FAN53555_VENDOR_FAIRCHILD | |
646 | }, { | |
fc1111b8 GT |
647 | .name = "syr827", |
648 | .driver_data = FAN53555_VENDOR_SILERGY | |
649 | }, { | |
650 | .name = "syr828", | |
ee30928a | 651 | .driver_data = FAN53555_VENDOR_SILERGY |
914df8fa JC |
652 | }, { |
653 | .name = "tcs4525", | |
b3cc8ec0 | 654 | .driver_data = FAN53526_VENDOR_TCS |
5eee5ece RH |
655 | }, { |
656 | .name = "tcs4526", | |
657 | .driver_data = FAN53526_VENDOR_TCS | |
ee30928a | 658 | }, |
49d8c599 YZ |
659 | { }, |
660 | }; | |
e80c47bd | 661 | MODULE_DEVICE_TABLE(i2c, fan53555_id); |
49d8c599 YZ |
662 | |
663 | static struct i2c_driver fan53555_regulator_driver = { | |
664 | .driver = { | |
665 | .name = "fan53555-regulator", | |
91f23d8f | 666 | .of_match_table = of_match_ptr(fan53555_dt_ids), |
49d8c599 YZ |
667 | }, |
668 | .probe = fan53555_regulator_probe, | |
49d8c599 YZ |
669 | .id_table = fan53555_id, |
670 | }; | |
671 | ||
672 | module_i2c_driver(fan53555_regulator_driver); | |
673 | ||
674 | MODULE_AUTHOR("Yunfan Zhang <yfzhang@marvell.com>"); | |
675 | MODULE_DESCRIPTION("FAN53555 regulator driver"); | |
676 | MODULE_LICENSE("GPL v2"); |