1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Split TWL6030 logic from twl-regulator.c: |
4 | * Copyright (C) 2008 David Brownell |
5 | * |
6 | * Copyright (C) 2016 Nicolae Rosia <nicolae.rosia@gmail.com> |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/string.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/init.h> |
13 | #include <linux/err.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/of.h> |
16 | #include <linux/regulator/driver.h> |
17 | #include <linux/regulator/machine.h> |
18 | #include <linux/regulator/of_regulator.h> |
19 | #include <linux/mfd/twl.h> |
20 | #include <linux/delay.h> |
21 | |
22 | struct twlreg_info { |
23 | /* start of regulator's PM_RECEIVER control register bank */ |
24 | u8 base; |
25 | |
26 | /* twl resource ID, for resource control state machine */ |
27 | u8 id; |
28 | |
29 | u8 flags; |
30 | |
31 | /* used by regulator core */ |
32 | struct regulator_desc desc; |
33 | |
34 | /* chip specific features */ |
35 | unsigned long features; |
36 | |
37 | /* data passed from board for external get/set voltage */ |
38 | void *data; |
39 | }; |
40 | |
41 | |
42 | /* LDO control registers ... offset is from the base of its register bank. |
43 | * The first three registers of all power resource banks help hardware to |
44 | * manage the various resource groups. |
45 | */ |
46 | /* Common offset in TWL4030/6030 */ |
47 | #define VREG_GRP 0 |
48 | /* TWL6030 register offsets */ |
49 | #define VREG_TRANS 1 |
50 | #define VREG_STATE 2 |
51 | #define VREG_VOLTAGE 3 |
52 | #define VREG_VOLTAGE_SMPS 4 |
53 | /* TWL6030 Misc register offsets */ |
54 | #define VREG_BC_ALL 1 |
55 | #define VREG_BC_REF 2 |
56 | #define VREG_BC_PROC 3 |
57 | #define VREG_BC_CLK_RST 4 |
58 | |
59 | /* TWL6030 LDO register values for VREG_VOLTAGE */ |
60 | #define TWL6030_VREG_VOLTAGE_WR_S BIT(7) |
61 | |
62 | /* TWL6030 LDO register values for CFG_STATE */ |
63 | #define TWL6030_CFG_STATE_OFF 0x00 |
64 | #define TWL6030_CFG_STATE_ON 0x01 |
65 | #define TWL6030_CFG_STATE_OFF2 0x02 |
66 | #define TWL6030_CFG_STATE_SLEEP 0x03 |
67 | #define TWL6030_CFG_STATE_GRP_SHIFT 5 |
68 | #define TWL6030_CFG_STATE_APP_SHIFT 2 |
69 | #define TWL6030_CFG_STATE_MASK 0x03 |
70 | #define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT) |
71 | #define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ |
72 | TWL6030_CFG_STATE_APP_SHIFT) |
73 | |
74 | /* Flags for SMPS Voltage reading and LDO reading*/ |
75 | #define SMPS_OFFSET_EN BIT(0) |
76 | #define SMPS_EXTENDED_EN BIT(1) |
77 | #define TWL_6030_WARM_RESET BIT(3) |
78 | |
79 | /* twl6032 SMPS EPROM values */ |
80 | #define TWL6030_SMPS_OFFSET 0xB0 |
81 | #define TWL6030_SMPS_MULT 0xB3 |
82 | #define SMPS_MULTOFFSET_SMPS4 BIT(0) |
83 | #define SMPS_MULTOFFSET_VIO BIT(1) |
84 | #define SMPS_MULTOFFSET_SMPS3 BIT(6) |
85 | |
86 | static inline int |
87 | twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset) |
88 | { |
89 | u8 value; |
90 | int status; |
91 | |
92 | status = twl_i2c_read_u8(mod_no: slave_subgp, |
93 | val: &value, reg: info->base + offset); |
94 | return (status < 0) ? status : value; |
95 | } |
96 | |
97 | static inline int |
98 | twlreg_write(struct twlreg_info *info, unsigned slave_subgp, unsigned offset, |
99 | u8 value) |
100 | { |
101 | return twl_i2c_write_u8(mod_no: slave_subgp, |
102 | val: value, reg: info->base + offset); |
103 | } |
104 | |
105 | /* generic power resource operations, which work on all regulators */ |
106 | static int twlreg_grp(struct regulator_dev *rdev) |
107 | { |
108 | return twlreg_read(info: rdev_get_drvdata(rdev), slave_subgp: TWL_MODULE_PM_RECEIVER, |
109 | VREG_GRP); |
110 | } |
111 | |
112 | /* |
113 | * Enable/disable regulators by joining/leaving the P1 (processor) group. |
114 | * We assume nobody else is updating the DEV_GRP registers. |
115 | */ |
116 | /* definition for 6030 family */ |
117 | #define P3_GRP_6030 BIT(2) /* secondary processor, modem, etc */ |
118 | #define P2_GRP_6030 BIT(1) /* "peripherals" */ |
119 | #define P1_GRP_6030 BIT(0) /* CPU/Linux */ |
120 | |
121 | static int twl6030reg_is_enabled(struct regulator_dev *rdev) |
122 | { |
123 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
124 | int grp = 0, val; |
125 | |
126 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) { |
127 | grp = twlreg_grp(rdev); |
128 | if (grp < 0) |
129 | return grp; |
130 | grp &= P1_GRP_6030; |
131 | val = twlreg_read(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_STATE); |
132 | val = TWL6030_CFG_STATE_APP(val); |
133 | } else { |
134 | val = twlreg_read(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_STATE); |
135 | val &= TWL6030_CFG_STATE_MASK; |
136 | grp = 1; |
137 | } |
138 | |
139 | return grp && (val == TWL6030_CFG_STATE_ON); |
140 | } |
141 | |
142 | #define PB_I2C_BUSY BIT(0) |
143 | #define PB_I2C_BWEN BIT(1) |
144 | |
145 | |
146 | static int twl6030reg_enable(struct regulator_dev *rdev) |
147 | { |
148 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
149 | int grp = 0; |
150 | int ret; |
151 | |
152 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) |
153 | grp = twlreg_grp(rdev); |
154 | if (grp < 0) |
155 | return grp; |
156 | |
157 | ret = twlreg_write(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_STATE, |
158 | value: grp << TWL6030_CFG_STATE_GRP_SHIFT | |
159 | TWL6030_CFG_STATE_ON); |
160 | return ret; |
161 | } |
162 | |
163 | static int twl6030reg_disable(struct regulator_dev *rdev) |
164 | { |
165 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
166 | int grp = 0; |
167 | int ret; |
168 | |
169 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) |
170 | grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030; |
171 | |
172 | /* For 6030, set the off state for all grps enabled */ |
173 | ret = twlreg_write(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_STATE, |
174 | value: (grp) << TWL6030_CFG_STATE_GRP_SHIFT | |
175 | TWL6030_CFG_STATE_OFF); |
176 | |
177 | return ret; |
178 | } |
179 | |
180 | static int twl6030reg_get_status(struct regulator_dev *rdev) |
181 | { |
182 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
183 | int val; |
184 | |
185 | val = twlreg_grp(rdev); |
186 | if (val < 0) |
187 | return val; |
188 | |
189 | val = twlreg_read(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_STATE); |
190 | |
191 | if (info->features & TWL6032_SUBCLASS) |
192 | val &= TWL6030_CFG_STATE_MASK; |
193 | else |
194 | val = TWL6030_CFG_STATE_APP(val); |
195 | |
196 | switch (val) { |
197 | case TWL6030_CFG_STATE_ON: |
198 | return REGULATOR_STATUS_NORMAL; |
199 | |
200 | case TWL6030_CFG_STATE_SLEEP: |
201 | return REGULATOR_STATUS_STANDBY; |
202 | |
203 | case TWL6030_CFG_STATE_OFF: |
204 | case TWL6030_CFG_STATE_OFF2: |
205 | default: |
206 | break; |
207 | } |
208 | |
209 | return REGULATOR_STATUS_OFF; |
210 | } |
211 | |
212 | static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) |
213 | { |
214 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
215 | int grp = 0; |
216 | int val; |
217 | |
218 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) |
219 | grp = twlreg_grp(rdev); |
220 | |
221 | if (grp < 0) |
222 | return grp; |
223 | |
224 | /* Compose the state register settings */ |
225 | val = grp << TWL6030_CFG_STATE_GRP_SHIFT; |
226 | /* We can only set the mode through state machine commands... */ |
227 | switch (mode) { |
228 | case REGULATOR_MODE_NORMAL: |
229 | val |= TWL6030_CFG_STATE_ON; |
230 | break; |
231 | case REGULATOR_MODE_STANDBY: |
232 | val |= TWL6030_CFG_STATE_SLEEP; |
233 | break; |
234 | |
235 | default: |
236 | return -EINVAL; |
237 | } |
238 | |
239 | return twlreg_write(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_STATE, value: val); |
240 | } |
241 | |
242 | static int twl6030coresmps_set_voltage(struct regulator_dev *rdev, int min_uV, |
243 | int max_uV, unsigned *selector) |
244 | { |
245 | return -ENODEV; |
246 | } |
247 | |
248 | static int twl6030coresmps_get_voltage(struct regulator_dev *rdev) |
249 | { |
250 | return -ENODEV; |
251 | } |
252 | |
253 | static const struct regulator_ops twl6030coresmps_ops = { |
254 | .set_voltage = twl6030coresmps_set_voltage, |
255 | .get_voltage = twl6030coresmps_get_voltage, |
256 | }; |
257 | |
258 | static int |
259 | twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) |
260 | { |
261 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
262 | |
263 | if (info->flags & TWL_6030_WARM_RESET) |
264 | selector |= TWL6030_VREG_VOLTAGE_WR_S; |
265 | |
266 | return twlreg_write(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, |
267 | value: selector); |
268 | } |
269 | |
270 | static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev) |
271 | { |
272 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
273 | int vsel = twlreg_read(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE); |
274 | |
275 | if (info->flags & TWL_6030_WARM_RESET) |
276 | vsel &= ~TWL6030_VREG_VOLTAGE_WR_S; |
277 | |
278 | return vsel; |
279 | } |
280 | |
281 | static const struct regulator_ops twl6030ldo_ops = { |
282 | .list_voltage = regulator_list_voltage_linear_range, |
283 | |
284 | .set_voltage_sel = twl6030ldo_set_voltage_sel, |
285 | .get_voltage_sel = twl6030ldo_get_voltage_sel, |
286 | |
287 | .enable = twl6030reg_enable, |
288 | .disable = twl6030reg_disable, |
289 | .is_enabled = twl6030reg_is_enabled, |
290 | |
291 | .set_mode = twl6030reg_set_mode, |
292 | |
293 | .get_status = twl6030reg_get_status, |
294 | }; |
295 | |
296 | static const struct regulator_ops twl6030fixed_ops = { |
297 | .list_voltage = regulator_list_voltage_linear, |
298 | |
299 | .enable = twl6030reg_enable, |
300 | .disable = twl6030reg_disable, |
301 | .is_enabled = twl6030reg_is_enabled, |
302 | |
303 | .set_mode = twl6030reg_set_mode, |
304 | |
305 | .get_status = twl6030reg_get_status, |
306 | }; |
307 | |
308 | /* |
309 | * SMPS status and control |
310 | */ |
311 | |
312 | static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index) |
313 | { |
314 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
315 | |
316 | int voltage = 0; |
317 | |
318 | switch (info->flags) { |
319 | case SMPS_OFFSET_EN: |
320 | voltage = 100000; |
321 | fallthrough; |
322 | case 0: |
323 | switch (index) { |
324 | case 0: |
325 | voltage = 0; |
326 | break; |
327 | case 58: |
328 | voltage = 1350 * 1000; |
329 | break; |
330 | case 59: |
331 | voltage = 1500 * 1000; |
332 | break; |
333 | case 60: |
334 | voltage = 1800 * 1000; |
335 | break; |
336 | case 61: |
337 | voltage = 1900 * 1000; |
338 | break; |
339 | case 62: |
340 | voltage = 2100 * 1000; |
341 | break; |
342 | default: |
343 | voltage += (600000 + (12500 * (index - 1))); |
344 | } |
345 | break; |
346 | case SMPS_EXTENDED_EN: |
347 | switch (index) { |
348 | case 0: |
349 | voltage = 0; |
350 | break; |
351 | case 58: |
352 | voltage = 2084 * 1000; |
353 | break; |
354 | case 59: |
355 | voltage = 2315 * 1000; |
356 | break; |
357 | case 60: |
358 | voltage = 2778 * 1000; |
359 | break; |
360 | case 61: |
361 | voltage = 2932 * 1000; |
362 | break; |
363 | case 62: |
364 | voltage = 3241 * 1000; |
365 | break; |
366 | default: |
367 | voltage = (1852000 + (38600 * (index - 1))); |
368 | } |
369 | break; |
370 | case SMPS_OFFSET_EN | SMPS_EXTENDED_EN: |
371 | switch (index) { |
372 | case 0: |
373 | voltage = 0; |
374 | break; |
375 | case 58: |
376 | voltage = 4167 * 1000; |
377 | break; |
378 | case 59: |
379 | voltage = 2315 * 1000; |
380 | break; |
381 | case 60: |
382 | voltage = 2778 * 1000; |
383 | break; |
384 | case 61: |
385 | voltage = 2932 * 1000; |
386 | break; |
387 | case 62: |
388 | voltage = 3241 * 1000; |
389 | break; |
390 | default: |
391 | voltage = (2161000 + (38600 * (index - 1))); |
392 | } |
393 | break; |
394 | } |
395 | |
396 | return voltage; |
397 | } |
398 | |
399 | static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV, |
400 | int max_uV) |
401 | { |
402 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
403 | int vsel = 0; |
404 | |
405 | switch (info->flags) { |
406 | case 0: |
407 | if (min_uV == 0) |
408 | vsel = 0; |
409 | else if ((min_uV >= 600000) && (min_uV <= 1300000)) { |
410 | vsel = DIV_ROUND_UP(min_uV - 600000, 12500); |
411 | vsel++; |
412 | } |
413 | /* Values 1..57 for vsel are linear and can be calculated |
414 | * values 58..62 are non linear. |
415 | */ |
416 | else if ((min_uV > 1900000) && (min_uV <= 2100000)) |
417 | vsel = 62; |
418 | else if ((min_uV > 1800000) && (min_uV <= 1900000)) |
419 | vsel = 61; |
420 | else if ((min_uV > 1500000) && (min_uV <= 1800000)) |
421 | vsel = 60; |
422 | else if ((min_uV > 1350000) && (min_uV <= 1500000)) |
423 | vsel = 59; |
424 | else if ((min_uV > 1300000) && (min_uV <= 1350000)) |
425 | vsel = 58; |
426 | else |
427 | return -EINVAL; |
428 | break; |
429 | case SMPS_OFFSET_EN: |
430 | if (min_uV == 0) |
431 | vsel = 0; |
432 | else if ((min_uV >= 700000) && (min_uV <= 1420000)) { |
433 | vsel = DIV_ROUND_UP(min_uV - 700000, 12500); |
434 | vsel++; |
435 | } |
436 | /* Values 1..57 for vsel are linear and can be calculated |
437 | * values 58..62 are non linear. |
438 | */ |
439 | else if ((min_uV > 1900000) && (min_uV <= 2100000)) |
440 | vsel = 62; |
441 | else if ((min_uV > 1800000) && (min_uV <= 1900000)) |
442 | vsel = 61; |
443 | else if ((min_uV > 1500000) && (min_uV <= 1800000)) |
444 | vsel = 60; |
445 | else if ((min_uV > 1350000) && (min_uV <= 1500000)) |
446 | vsel = 59; |
447 | else |
448 | return -EINVAL; |
449 | break; |
450 | case SMPS_EXTENDED_EN: |
451 | if (min_uV == 0) { |
452 | vsel = 0; |
453 | } else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { |
454 | vsel = DIV_ROUND_UP(min_uV - 1852000, 38600); |
455 | vsel++; |
456 | } |
457 | break; |
458 | case SMPS_OFFSET_EN|SMPS_EXTENDED_EN: |
459 | if (min_uV == 0) { |
460 | vsel = 0; |
461 | } else if ((min_uV >= 2161000) && (min_uV <= 4321000)) { |
462 | vsel = DIV_ROUND_UP(min_uV - 2161000, 38600); |
463 | vsel++; |
464 | } |
465 | break; |
466 | } |
467 | |
468 | return vsel; |
469 | } |
470 | |
471 | static int twl6030smps_set_voltage_sel(struct regulator_dev *rdev, |
472 | unsigned int selector) |
473 | { |
474 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
475 | |
476 | return twlreg_write(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS, |
477 | value: selector); |
478 | } |
479 | |
480 | static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) |
481 | { |
482 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
483 | |
484 | return twlreg_read(info, slave_subgp: TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS); |
485 | } |
486 | |
487 | static const struct regulator_ops twlsmps_ops = { |
488 | .list_voltage = twl6030smps_list_voltage, |
489 | .map_voltage = twl6030smps_map_voltage, |
490 | |
491 | .set_voltage_sel = twl6030smps_set_voltage_sel, |
492 | .get_voltage_sel = twl6030smps_get_voltage_sel, |
493 | |
494 | .enable = twl6030reg_enable, |
495 | .disable = twl6030reg_disable, |
496 | .is_enabled = twl6030reg_is_enabled, |
497 | |
498 | .set_mode = twl6030reg_set_mode, |
499 | |
500 | .get_status = twl6030reg_get_status, |
501 | }; |
502 | |
503 | /*----------------------------------------------------------------------*/ |
504 | static const struct linear_range twl6030ldo_linear_range[] = { |
505 | REGULATOR_LINEAR_RANGE(0, 0, 0, 0), |
506 | REGULATOR_LINEAR_RANGE(1000000, 1, 24, 100000), |
507 | REGULATOR_LINEAR_RANGE(2750000, 31, 31, 0), |
508 | }; |
509 | |
510 | #define TWL6030_ADJUSTABLE_SMPS(label) \ |
511 | static const struct twlreg_info TWL6030_INFO_##label = { \ |
512 | .desc = { \ |
513 | .name = #label, \ |
514 | .id = TWL6030_REG_##label, \ |
515 | .ops = &twl6030coresmps_ops, \ |
516 | .type = REGULATOR_VOLTAGE, \ |
517 | .owner = THIS_MODULE, \ |
518 | }, \ |
519 | } |
520 | |
521 | #define TWL6030_ADJUSTABLE_LDO(label, offset) \ |
522 | static const struct twlreg_info TWL6030_INFO_##label = { \ |
523 | .base = offset, \ |
524 | .desc = { \ |
525 | .name = #label, \ |
526 | .id = TWL6030_REG_##label, \ |
527 | .n_voltages = 32, \ |
528 | .linear_ranges = twl6030ldo_linear_range, \ |
529 | .n_linear_ranges = ARRAY_SIZE(twl6030ldo_linear_range), \ |
530 | .ops = &twl6030ldo_ops, \ |
531 | .type = REGULATOR_VOLTAGE, \ |
532 | .owner = THIS_MODULE, \ |
533 | }, \ |
534 | } |
535 | |
536 | #define TWL6032_ADJUSTABLE_LDO(label, offset) \ |
537 | static const struct twlreg_info TWL6032_INFO_##label = { \ |
538 | .base = offset, \ |
539 | .features = TWL6032_SUBCLASS, \ |
540 | .desc = { \ |
541 | .name = #label, \ |
542 | .id = TWL6032_REG_##label, \ |
543 | .n_voltages = 32, \ |
544 | .linear_ranges = twl6030ldo_linear_range, \ |
545 | .n_linear_ranges = ARRAY_SIZE(twl6030ldo_linear_range), \ |
546 | .ops = &twl6030ldo_ops, \ |
547 | .type = REGULATOR_VOLTAGE, \ |
548 | .owner = THIS_MODULE, \ |
549 | }, \ |
550 | } |
551 | |
552 | #define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ |
553 | static const struct twlreg_info TWLFIXED_INFO_##label = { \ |
554 | .base = offset, \ |
555 | .id = 0, \ |
556 | .desc = { \ |
557 | .name = #label, \ |
558 | .id = TWL6030##_REG_##label, \ |
559 | .n_voltages = 1, \ |
560 | .ops = &twl6030fixed_ops, \ |
561 | .type = REGULATOR_VOLTAGE, \ |
562 | .owner = THIS_MODULE, \ |
563 | .min_uV = mVolts * 1000, \ |
564 | .enable_time = turnon_delay, \ |
565 | .of_map_mode = NULL, \ |
566 | }, \ |
567 | } |
568 | |
569 | #define TWL6032_ADJUSTABLE_SMPS(label, offset) \ |
570 | static const struct twlreg_info TWLSMPS_INFO_##label = { \ |
571 | .base = offset, \ |
572 | .features = TWL6032_SUBCLASS, \ |
573 | .desc = { \ |
574 | .name = #label, \ |
575 | .id = TWL6032_REG_##label, \ |
576 | .n_voltages = 63, \ |
577 | .ops = &twlsmps_ops, \ |
578 | .type = REGULATOR_VOLTAGE, \ |
579 | .owner = THIS_MODULE, \ |
580 | }, \ |
581 | } |
582 | |
583 | /* VUSBCP is managed *only* by the USB subchip */ |
584 | /* 6030 REG with base as PMC Slave Misc : 0x0030 */ |
585 | /* Turnon-delay and remap configuration values for 6030 are not |
586 | verified since the specification is not public */ |
587 | TWL6030_ADJUSTABLE_SMPS(VDD1); |
588 | TWL6030_ADJUSTABLE_SMPS(VDD2); |
589 | TWL6030_ADJUSTABLE_SMPS(VDD3); |
590 | TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54); |
591 | TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58); |
592 | TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c); |
593 | TWL6030_ADJUSTABLE_LDO(VMMC, 0x68); |
594 | TWL6030_ADJUSTABLE_LDO(VPP, 0x6c); |
595 | TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74); |
596 | /* 6025 are renamed compared to 6030 versions */ |
597 | TWL6032_ADJUSTABLE_LDO(LDO2, 0x54); |
598 | TWL6032_ADJUSTABLE_LDO(LDO4, 0x58); |
599 | TWL6032_ADJUSTABLE_LDO(LDO3, 0x5c); |
600 | TWL6032_ADJUSTABLE_LDO(LDO5, 0x68); |
601 | TWL6032_ADJUSTABLE_LDO(LDO1, 0x6c); |
602 | TWL6032_ADJUSTABLE_LDO(LDO7, 0x74); |
603 | TWL6032_ADJUSTABLE_LDO(LDO6, 0x60); |
604 | TWL6032_ADJUSTABLE_LDO(LDOLN, 0x64); |
605 | TWL6032_ADJUSTABLE_LDO(LDOUSB, 0x70); |
606 | TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0); |
607 | TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0); |
608 | TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0); |
609 | TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0); |
610 | TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0); |
611 | TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0); |
612 | TWL6032_ADJUSTABLE_SMPS(SMPS3, 0x34); |
613 | TWL6032_ADJUSTABLE_SMPS(SMPS4, 0x10); |
614 | TWL6032_ADJUSTABLE_SMPS(VIO, 0x16); |
615 | |
616 | static u8 twl_get_smps_offset(void) |
617 | { |
618 | u8 value; |
619 | |
620 | twl_i2c_read_u8(mod_no: TWL_MODULE_PM_RECEIVER, val: &value, |
621 | TWL6030_SMPS_OFFSET); |
622 | return value; |
623 | } |
624 | |
625 | static u8 twl_get_smps_mult(void) |
626 | { |
627 | u8 value; |
628 | |
629 | twl_i2c_read_u8(mod_no: TWL_MODULE_PM_RECEIVER, val: &value, |
630 | TWL6030_SMPS_MULT); |
631 | return value; |
632 | } |
633 | |
634 | #define TWL_OF_MATCH(comp, family, label) \ |
635 | { \ |
636 | .compatible = comp, \ |
637 | .data = &family##_INFO_##label, \ |
638 | } |
639 | |
640 | #define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label) |
641 | #define TWL6032_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6032, label) |
642 | #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label) |
643 | #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label) |
644 | |
645 | static const struct of_device_id twl_of_match[] = { |
646 | TWL6030_OF_MATCH("ti,twl6030-vdd1" , VDD1), |
647 | TWL6030_OF_MATCH("ti,twl6030-vdd2" , VDD2), |
648 | TWL6030_OF_MATCH("ti,twl6030-vdd3" , VDD3), |
649 | TWL6030_OF_MATCH("ti,twl6030-vaux1" , VAUX1_6030), |
650 | TWL6030_OF_MATCH("ti,twl6030-vaux2" , VAUX2_6030), |
651 | TWL6030_OF_MATCH("ti,twl6030-vaux3" , VAUX3_6030), |
652 | TWL6030_OF_MATCH("ti,twl6030-vmmc" , VMMC), |
653 | TWL6030_OF_MATCH("ti,twl6030-vpp" , VPP), |
654 | TWL6030_OF_MATCH("ti,twl6030-vusim" , VUSIM), |
655 | TWL6032_OF_MATCH("ti,twl6032-ldo2" , LDO2), |
656 | TWL6032_OF_MATCH("ti,twl6032-ldo4" , LDO4), |
657 | TWL6032_OF_MATCH("ti,twl6032-ldo3" , LDO3), |
658 | TWL6032_OF_MATCH("ti,twl6032-ldo5" , LDO5), |
659 | TWL6032_OF_MATCH("ti,twl6032-ldo1" , LDO1), |
660 | TWL6032_OF_MATCH("ti,twl6032-ldo7" , LDO7), |
661 | TWL6032_OF_MATCH("ti,twl6032-ldo6" , LDO6), |
662 | TWL6032_OF_MATCH("ti,twl6032-ldoln" , LDOLN), |
663 | TWL6032_OF_MATCH("ti,twl6032-ldousb" , LDOUSB), |
664 | TWLFIXED_OF_MATCH("ti,twl6030-vana" , VANA), |
665 | TWLFIXED_OF_MATCH("ti,twl6030-vcxio" , VCXIO), |
666 | TWLFIXED_OF_MATCH("ti,twl6030-vdac" , VDAC), |
667 | TWLFIXED_OF_MATCH("ti,twl6030-vusb" , VUSB), |
668 | TWLFIXED_OF_MATCH("ti,twl6030-v1v8" , V1V8), |
669 | TWLFIXED_OF_MATCH("ti,twl6030-v2v1" , V2V1), |
670 | TWLSMPS_OF_MATCH("ti,twl6032-smps3" , SMPS3), |
671 | TWLSMPS_OF_MATCH("ti,twl6032-smps4" , SMPS4), |
672 | TWLSMPS_OF_MATCH("ti,twl6032-vio" , VIO), |
673 | {}, |
674 | }; |
675 | MODULE_DEVICE_TABLE(of, twl_of_match); |
676 | |
677 | static int twlreg_probe(struct platform_device *pdev) |
678 | { |
679 | int id; |
680 | struct twlreg_info *info; |
681 | const struct twlreg_info *template; |
682 | struct regulator_init_data *initdata; |
683 | struct regulation_constraints *c; |
684 | struct regulator_dev *rdev; |
685 | struct regulator_config config = { }; |
686 | struct device_node *np = pdev->dev.of_node; |
687 | |
688 | template = of_device_get_match_data(dev: &pdev->dev); |
689 | if (!template) |
690 | return -ENODEV; |
691 | |
692 | id = template->desc.id; |
693 | initdata = of_get_regulator_init_data(dev: &pdev->dev, node: np, desc: &template->desc); |
694 | if (!initdata) |
695 | return -EINVAL; |
696 | |
697 | info = devm_kmemdup(dev: &pdev->dev, src: template, len: sizeof(*info), GFP_KERNEL); |
698 | if (!info) |
699 | return -ENOMEM; |
700 | |
701 | /* Constrain board-specific capabilities according to what |
702 | * this driver and the chip itself can actually do. |
703 | */ |
704 | c = &initdata->constraints; |
705 | c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY; |
706 | c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE |
707 | | REGULATOR_CHANGE_MODE |
708 | | REGULATOR_CHANGE_STATUS; |
709 | |
710 | switch (id) { |
711 | case TWL6032_REG_SMPS3: |
712 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3) |
713 | info->flags |= SMPS_EXTENDED_EN; |
714 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3) |
715 | info->flags |= SMPS_OFFSET_EN; |
716 | break; |
717 | case TWL6032_REG_SMPS4: |
718 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4) |
719 | info->flags |= SMPS_EXTENDED_EN; |
720 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4) |
721 | info->flags |= SMPS_OFFSET_EN; |
722 | break; |
723 | case TWL6032_REG_VIO: |
724 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO) |
725 | info->flags |= SMPS_EXTENDED_EN; |
726 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO) |
727 | info->flags |= SMPS_OFFSET_EN; |
728 | break; |
729 | } |
730 | |
731 | if (of_property_read_bool(np, propname: "ti,retain-on-reset" )) |
732 | info->flags |= TWL_6030_WARM_RESET; |
733 | |
734 | config.dev = &pdev->dev; |
735 | config.init_data = initdata; |
736 | config.driver_data = info; |
737 | config.of_node = np; |
738 | |
739 | rdev = devm_regulator_register(dev: &pdev->dev, regulator_desc: &info->desc, config: &config); |
740 | if (IS_ERR(ptr: rdev)) { |
741 | dev_err(&pdev->dev, "can't register %s, %ld\n" , |
742 | info->desc.name, PTR_ERR(rdev)); |
743 | return PTR_ERR(ptr: rdev); |
744 | } |
745 | platform_set_drvdata(pdev, data: rdev); |
746 | |
747 | /* NOTE: many regulators support short-circuit IRQs (presentable |
748 | * as REGULATOR_OVER_CURRENT notifications?) configured via: |
749 | * - SC_CONFIG |
750 | * - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4) |
751 | * - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2) |
752 | * - IT_CONFIG |
753 | */ |
754 | |
755 | return 0; |
756 | } |
757 | |
758 | MODULE_ALIAS("platform:twl6030_reg" ); |
759 | |
760 | static struct platform_driver twlreg_driver = { |
761 | .probe = twlreg_probe, |
762 | /* NOTE: short name, to work around driver model truncation of |
763 | * "twl_regulator.12" (and friends) to "twl_regulator.1". |
764 | */ |
765 | .driver = { |
766 | .name = "twl6030_reg" , |
767 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
768 | .of_match_table = of_match_ptr(twl_of_match), |
769 | }, |
770 | }; |
771 | |
772 | static int __init twlreg_init(void) |
773 | { |
774 | return platform_driver_register(&twlreg_driver); |
775 | } |
776 | subsys_initcall(twlreg_init); |
777 | |
778 | static void __exit twlreg_exit(void) |
779 | { |
780 | platform_driver_unregister(&twlreg_driver); |
781 | } |
782 | module_exit(twlreg_exit) |
783 | |
784 | MODULE_DESCRIPTION("TWL6030 regulator driver" ); |
785 | MODULE_LICENSE("GPL" ); |
786 | |