1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2011
5 * Ben Gray <ben.r.gray@gmail.com>.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 /*
32 * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
33 *
34 * This driver covers the voltages regulators (LDO), allows for enabling &
35 * disabling the voltage output and adjusting the voltage level.
36 *
37 * Voltage regulators can belong to different power groups, in this driver we
38 * put the regulators under our control in the "Application power group".
39 *
40 *
41 * FLATTENED DEVICE TREE (FDT)
42 * Startup override settings can be specified in the FDT, if they are they
43 * should be under the twl parent device and take the following form:
44 *
45 * voltage-regulators = "name1", "millivolts1",
46 * "name2", "millivolts2";
47 *
48 * Each override should be a pair, the first entry is the name of the regulator
49 * the second is the voltage (in millivolts) to set for the given regulator.
50 *
51 */
52
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/kernel.h>
56 #include <sys/lock.h>
57 #include <sys/module.h>
58 #include <sys/bus.h>
59 #include <sys/resource.h>
60 #include <sys/rman.h>
61 #include <sys/sysctl.h>
62 #include <sys/sx.h>
63 #include <sys/malloc.h>
64
65 #include <machine/bus.h>
66 #include <machine/resource.h>
67 #include <machine/intr.h>
68
69 #include <dev/ofw/openfirm.h>
70 #include <dev/ofw/ofw_bus.h>
71
72 #include "twl.h"
73 #include "twl_vreg.h"
74
75 static int twl_vreg_debug = 1;
76
77 /*
78 * Power Groups bits for the 4030 and 6030 devices
79 */
80 #define TWL4030_P3_GRP 0x80 /* Peripherals, power group */
81 #define TWL4030_P2_GRP 0x40 /* Modem power group */
82 #define TWL4030_P1_GRP 0x20 /* Application power group (FreeBSD control) */
83
84 #define TWL6030_P3_GRP 0x04 /* Modem power group */
85 #define TWL6030_P2_GRP 0x02 /* Connectivity power group */
86 #define TWL6030_P1_GRP 0x01 /* Application power group (FreeBSD control) */
87
88 /*
89 * Register offsets within a LDO regulator register set
90 */
91 #define TWL_VREG_GRP 0x00 /* Regulator GRP register */
92 #define TWL_VREG_STATE 0x02
93 #define TWL_VREG_VSEL 0x03 /* Voltage select register */
94
95 #define UNDF 0xFFFF
96
97 static const uint16_t twl6030_voltages[] = {
98 0000, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
99 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400,
100 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200,
101 3300, UNDF, UNDF, UNDF, UNDF, UNDF, UNDF, 2750
102 };
103
104 static const uint16_t twl4030_vaux1_voltages[] = {
105 1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
106 };
107 static const uint16_t twl4030_vaux2_voltages[] = {
108 1700, 1700, 1900, 1300, 1500, 1800, 2000, 2500,
109 2100, 2800, 2200, 2300, 2400, 2400, 2400, 2400
110 };
111 static const uint16_t twl4030_vaux3_voltages[] = {
112 1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
113 };
114 static const uint16_t twl4030_vaux4_voltages[] = {
115 700, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
116 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
117 };
118 static const uint16_t twl4030_vmmc1_voltages[] = {
119 1850, 2850, 3000, 3150
120 };
121 static const uint16_t twl4030_vmmc2_voltages[] = {
122 1000, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
123 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
124 };
125 static const uint16_t twl4030_vpll1_voltages[] = {
126 1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
127 };
128 static const uint16_t twl4030_vpll2_voltages[] = {
129 700, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
130 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
131 };
132 static const uint16_t twl4030_vsim_voltages[] = {
133 1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
134 };
135 static const uint16_t twl4030_vdac_voltages[] = {
136 1200, 1300, 1800, 1800
137 };
138 #if 0 /* vdd1, vdd2, vdio, not currently used. */
139 static const uint16_t twl4030_vdd1_voltages[] = {
140 800, 1450
141 };
142 static const uint16_t twl4030_vdd2_voltages[] = {
143 800, 1450, 1500
144 };
145 static const uint16_t twl4030_vio_voltages[] = {
146 1800, 1850
147 };
148 #endif
149 static const uint16_t twl4030_vintana2_voltages[] = {
150 2500, 2750
151 };
152
153 /**
154 * Support voltage regulators for the different IC's
155 */
156 struct twl_regulator {
157 const char *name;
158 uint8_t subdev;
159 uint8_t regbase;
160
161 uint16_t fixedvoltage;
162
163 const uint16_t *voltages;
164 uint32_t num_voltages;
165 };
166
167 #define TWL_REGULATOR_ADJUSTABLE(name, subdev, reg, voltages) \
168 { name, subdev, reg, 0, voltages, (sizeof(voltages)/sizeof(voltages[0])) }
169 #define TWL_REGULATOR_FIXED(name, subdev, reg, voltage) \
170 { name, subdev, reg, voltage, NULL, 0 }
171
172 static const struct twl_regulator twl4030_regulators[] = {
173 TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x17, twl4030_vaux1_voltages),
174 TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x1B, twl4030_vaux2_voltages),
175 TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x1F, twl4030_vaux3_voltages),
176 TWL_REGULATOR_ADJUSTABLE("vaux4", 0, 0x23, twl4030_vaux4_voltages),
177 TWL_REGULATOR_ADJUSTABLE("vmmc1", 0, 0x27, twl4030_vmmc1_voltages),
178 TWL_REGULATOR_ADJUSTABLE("vmmc2", 0, 0x2B, twl4030_vmmc2_voltages),
179 TWL_REGULATOR_ADJUSTABLE("vpll1", 0, 0x2F, twl4030_vpll1_voltages),
180 TWL_REGULATOR_ADJUSTABLE("vpll2", 0, 0x33, twl4030_vpll2_voltages),
181 TWL_REGULATOR_ADJUSTABLE("vsim", 0, 0x37, twl4030_vsim_voltages),
182 TWL_REGULATOR_ADJUSTABLE("vdac", 0, 0x3B, twl4030_vdac_voltages),
183 TWL_REGULATOR_ADJUSTABLE("vintana2", 0, 0x43, twl4030_vintana2_voltages),
184 TWL_REGULATOR_FIXED("vintana1", 0, 0x3F, 1500),
185 TWL_REGULATOR_FIXED("vintdig", 0, 0x47, 1500),
186 TWL_REGULATOR_FIXED("vusb1v5", 0, 0x71, 1500),
187 TWL_REGULATOR_FIXED("vusb1v8", 0, 0x74, 1800),
188 TWL_REGULATOR_FIXED("vusb3v1", 0, 0x77, 3100),
189 { NULL, 0, 0x00, 0, NULL, 0 }
190 };
191
192 static const struct twl_regulator twl6030_regulators[] = {
193 TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x84, twl6030_voltages),
194 TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x89, twl6030_voltages),
195 TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x8C, twl6030_voltages),
196 TWL_REGULATOR_ADJUSTABLE("vmmc", 0, 0x98, twl6030_voltages),
197 TWL_REGULATOR_ADJUSTABLE("vpp", 0, 0x9C, twl6030_voltages),
198 TWL_REGULATOR_ADJUSTABLE("vusim", 0, 0xA4, twl6030_voltages),
199 TWL_REGULATOR_FIXED("vmem", 0, 0x64, 1800),
200 TWL_REGULATOR_FIXED("vusb", 0, 0xA0, 3300),
201 TWL_REGULATOR_FIXED("v1v8", 0, 0x46, 1800),
202 TWL_REGULATOR_FIXED("v2v1", 0, 0x4C, 2100),
203 TWL_REGULATOR_FIXED("v1v29", 0, 0x40, 1290),
204 TWL_REGULATOR_FIXED("vcxio", 0, 0x90, 1800),
205 TWL_REGULATOR_FIXED("vdac", 0, 0x94, 1800),
206 TWL_REGULATOR_FIXED("vana", 0, 0x80, 2100),
207 { NULL, 0, 0x00, 0, NULL, 0 }
208 };
209
210 #define TWL_VREG_MAX_NAMELEN 32
211
212 struct twl_regulator_entry {
213 LIST_ENTRY(twl_regulator_entry) entries;
214 char name[TWL_VREG_MAX_NAMELEN];
215 struct sysctl_oid *oid;
216 uint8_t sub_dev; /* TWL sub-device group */
217 uint8_t reg_off; /* base register offset for the LDO */
218 uint16_t fixed_voltage; /* the (milli)voltage if LDO is fixed */
219 const uint16_t *supp_voltages; /* pointer to an array of possible voltages */
220 uint32_t num_supp_voltages; /* the number of supplied voltages */
221 };
222
223 struct twl_vreg_softc {
224 device_t sc_dev;
225 device_t sc_pdev;
226 struct sx sc_sx;
227
228 struct intr_config_hook sc_init_hook;
229 LIST_HEAD(twl_regulator_list, twl_regulator_entry) sc_vreg_list;
230 };
231
232 #define TWL_VREG_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx)
233 #define TWL_VREG_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx)
234 #define TWL_VREG_SLOCK(_sc) sx_slock(&(_sc)->sc_sx)
235 #define TWL_VREG_SUNLOCK(_sc) sx_sunlock(&(_sc)->sc_sx)
236 #define TWL_VREG_LOCK_INIT(_sc) sx_init(&(_sc)->sc_sx, "twl_vreg")
237 #define TWL_VREG_LOCK_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx);
238
239 #define TWL_VREG_ASSERT_LOCKED(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED);
240
241 #define TWL_VREG_LOCK_UPGRADE(_sc) \
242 do { \
243 while (!sx_try_upgrade(&(_sc)->sc_sx)) \
244 pause("twl_vreg_ex", (hz / 100)); \
245 } while(0)
246 #define TWL_VREG_LOCK_DOWNGRADE(_sc) sx_downgrade(&(_sc)->sc_sx);
247
248 /**
249 * twl_vreg_read_1 - read single register from the TWL device
250 * twl_vreg_write_1 - write a single register in the TWL device
251 * @sc: device context
252 * @clk: the clock device we're reading from / writing to
253 * @off: offset within the clock's register set
254 * @val: the value to write or a pointer to a variable to store the result
255 *
256 * RETURNS:
257 * Zero on success or an error code on failure.
258 */
259 static inline int
twl_vreg_read_1(struct twl_vreg_softc * sc,struct twl_regulator_entry * regulator,uint8_t off,uint8_t * val)260 twl_vreg_read_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
261 uint8_t off, uint8_t *val)
262 {
263 return (twl_read(sc->sc_pdev, regulator->sub_dev,
264 regulator->reg_off + off, val, 1));
265 }
266
267 static inline int
twl_vreg_write_1(struct twl_vreg_softc * sc,struct twl_regulator_entry * regulator,uint8_t off,uint8_t val)268 twl_vreg_write_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
269 uint8_t off, uint8_t val)
270 {
271 return (twl_write(sc->sc_pdev, regulator->sub_dev,
272 regulator->reg_off + off, &val, 1));
273 }
274
275 /**
276 * twl_millivolt_to_vsel - gets the vsel bit value to write into the register
277 * for a desired voltage and regulator
278 * @sc: the device soft context
279 * @regulator: pointer to the regulator device
280 * @millivolts: the millivolts to find the bit value for
281 * @vsel: upon return will contain the corresponding register value
282 *
283 * Accepts a (milli)voltage value and tries to find the closest match to the
284 * actual supported voltages for the given regulator. If a match is found
285 * within 100mv of the target, @vsel is written with the match and 0 is
286 * returned. If no voltage match is found the function returns an non-zero
287 * value.
288 *
289 * RETURNS:
290 * Zero on success or an error code on failure.
291 */
292 static int
twl_vreg_millivolt_to_vsel(struct twl_vreg_softc * sc,struct twl_regulator_entry * regulator,int millivolts,uint8_t * vsel)293 twl_vreg_millivolt_to_vsel(struct twl_vreg_softc *sc,
294 struct twl_regulator_entry *regulator, int millivolts, uint8_t *vsel)
295 {
296 int delta, smallest_delta;
297 unsigned i, closest_idx;
298
299 TWL_VREG_ASSERT_LOCKED(sc);
300
301 if (regulator->supp_voltages == NULL)
302 return (EINVAL);
303
304 /* Loop over the support voltages and try and find the closest match */
305 closest_idx = 0;
306 smallest_delta = 0x7fffffff;
307 for (i = 0; i < regulator->num_supp_voltages; i++) {
308 /* Ignore undefined values */
309 if (regulator->supp_voltages[i] == UNDF)
310 continue;
311
312 /* Calculate the difference */
313 delta = millivolts - (int)regulator->supp_voltages[i];
314 if (abs(delta) < smallest_delta) {
315 smallest_delta = abs(delta);
316 closest_idx = i;
317 }
318 }
319
320 /* Check we got a voltage that was within 100mv of the actual target, this
321 * is just a value I picked out of thin air.
322 */
323 if ((smallest_delta > 100) && (closest_idx < 0x100))
324 return (EINVAL);
325
326 *vsel = closest_idx;
327 return (0);
328 }
329
330 /**
331 * twl_vreg_is_regulator_enabled - returns the enabled status of the regulator
332 * @sc: the device soft context
333 * @regulator: pointer to the regulator device
334 * @enabled: stores the enabled status, zero disabled, non-zero enabled
335 *
336 * LOCKING:
337 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
338 * exclusive if not already but, if so, it will be downgraded again before
339 * returning.
340 *
341 * RETURNS:
342 * Zero on success or an error code on failure.
343 */
344 static int
twl_vreg_is_regulator_enabled(struct twl_vreg_softc * sc,struct twl_regulator_entry * regulator,int * enabled)345 twl_vreg_is_regulator_enabled(struct twl_vreg_softc *sc,
346 struct twl_regulator_entry *regulator, int *enabled)
347 {
348 int err;
349 uint8_t grp;
350 uint8_t state;
351 int xlocked;
352
353 if (enabled == NULL)
354 return (EINVAL);
355
356 TWL_VREG_ASSERT_LOCKED(sc);
357
358 xlocked = sx_xlocked(&sc->sc_sx);
359 if (!xlocked)
360 TWL_VREG_LOCK_UPGRADE(sc);
361
362 /* The status reading is different for the different devices */
363 if (twl_is_4030(sc->sc_pdev)) {
364 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &state);
365 if (err)
366 goto done;
367
368 *enabled = (state & TWL4030_P1_GRP);
369
370 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
371 /* Check the regulator is in the application group */
372 if (twl_is_6030(sc->sc_pdev)) {
373 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
374 if (err)
375 goto done;
376
377 if (!(grp & TWL6030_P1_GRP)) {
378 *enabled = 0; /* disabled */
379 goto done;
380 }
381 }
382
383 /* Read the application mode state and verify it's ON */
384 err = twl_vreg_read_1(sc, regulator, TWL_VREG_STATE, &state);
385 if (err)
386 goto done;
387
388 *enabled = ((state & 0x0C) == 0x04);
389
390 } else {
391 err = EINVAL;
392 }
393
394 done:
395 if (!xlocked)
396 TWL_VREG_LOCK_DOWNGRADE(sc);
397
398 return (err);
399 }
400
401 /**
402 * twl_vreg_disable_regulator - disables a voltage regulator
403 * @sc: the device soft context
404 * @regulator: pointer to the regulator device
405 *
406 * Disables the regulator which will stop the output drivers.
407 *
408 * LOCKING:
409 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
410 * exclusive if not already but, if so, it will be downgraded again before
411 * returning.
412 *
413 * RETURNS:
414 * Zero on success or a positive error code on failure.
415 */
416 static int
twl_vreg_disable_regulator(struct twl_vreg_softc * sc,struct twl_regulator_entry * regulator)417 twl_vreg_disable_regulator(struct twl_vreg_softc *sc,
418 struct twl_regulator_entry *regulator)
419 {
420 int err = 0;
421 uint8_t grp;
422 int xlocked;
423
424 TWL_VREG_ASSERT_LOCKED(sc);
425
426 xlocked = sx_xlocked(&sc->sc_sx);
427 if (!xlocked)
428 TWL_VREG_LOCK_UPGRADE(sc);
429
430 if (twl_is_4030(sc->sc_pdev)) {
431 /* Read the regulator CFG_GRP register */
432 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
433 if (err)
434 goto done;
435
436 /* On the TWL4030 we just need to remove the regulator from all the
437 * power groups.
438 */
439 grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
440 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
441
442 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
443 /* On TWL6030 we need to make sure we disable power for all groups */
444 if (twl_is_6030(sc->sc_pdev))
445 grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
446 else
447 grp = 0x00;
448
449 /* Write the resource state to "OFF" */
450 err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5));
451 }
452
453 done:
454 if (!xlocked)
455 TWL_VREG_LOCK_DOWNGRADE(sc);
456
457 return (err);
458 }
459
460 /**
461 * twl_vreg_enable_regulator - enables the voltage regulator
462 * @sc: the device soft context
463 * @regulator: pointer to the regulator device
464 *
465 * Enables the regulator which will enable the voltage out at the currently
466 * set voltage. Set the voltage before calling this function to avoid
467 * driving the voltage too high/low by mistake.
468 *
469 * LOCKING:
470 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
471 * exclusive if not already but, if so, it will be downgraded again before
472 * returning.
473 *
474 * RETURNS:
475 * Zero on success or a positive error code on failure.
476 */
477 static int
twl_vreg_enable_regulator(struct twl_vreg_softc * sc,struct twl_regulator_entry * regulator)478 twl_vreg_enable_regulator(struct twl_vreg_softc *sc,
479 struct twl_regulator_entry *regulator)
480 {
481 int err;
482 uint8_t grp;
483 int xlocked;
484
485 TWL_VREG_ASSERT_LOCKED(sc);
486
487 xlocked = sx_xlocked(&sc->sc_sx);
488 if (!xlocked)
489 TWL_VREG_LOCK_UPGRADE(sc);
490
491 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
492 if (err)
493 goto done;
494
495 /* Enable the regulator by ensuring it's in the application power group
496 * and is in the "on" state.
497 */
498 if (twl_is_4030(sc->sc_pdev)) {
499 /* On the TWL4030 we just need to ensure the regulator is in the right
500 * power domain, don't need to turn on explicitly like TWL6030.
501 */
502 grp |= TWL4030_P1_GRP;
503 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
504
505 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
506 if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
507 grp |= TWL6030_P1_GRP;
508 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
509 if (err)
510 goto done;
511 }
512
513 /* Write the resource state to "ON" */
514 err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5) | 0x01);
515 }
516
517 done:
518 if (!xlocked)
519 TWL_VREG_LOCK_DOWNGRADE(sc);
520
521 return (err);
522 }
523
524 /**
525 * twl_vreg_write_regulator_voltage - sets the voltage level on a regulator
526 * @sc: the device soft context
527 * @regulator: pointer to the regulator structure
528 * @millivolts: the voltage to set
529 *
530 * Sets the voltage output on a given regulator, if the regulator is not
531 * enabled, it will be enabled.
532 *
533 * LOCKING:
534 * On entry expects the TWL VREG lock to be held, may upgrade the lock to
535 * exclusive but if so it will be downgraded once again before returning.
536 *
537 * RETURNS:
538 * Zero on success or an error code on failure.
539 */
540 static int
twl_vreg_write_regulator_voltage(struct twl_vreg_softc * sc,struct twl_regulator_entry * regulator,int millivolts)541 twl_vreg_write_regulator_voltage(struct twl_vreg_softc *sc,
542 struct twl_regulator_entry *regulator, int millivolts)
543 {
544 int err;
545 uint8_t vsel;
546 int xlocked;
547
548 TWL_VREG_ASSERT_LOCKED(sc);
549
550 /* If millivolts is zero then we simply disable the output */
551 if (millivolts == 0)
552 return (twl_vreg_disable_regulator(sc, regulator));
553
554 /* If the regulator has a fixed voltage then check the setting matches
555 * and simply enable.
556 */
557 if (regulator->supp_voltages == NULL || regulator->num_supp_voltages == 0) {
558 if (millivolts != regulator->fixed_voltage)
559 return (EINVAL);
560
561 return (twl_vreg_enable_regulator(sc, regulator));
562 }
563
564 /* Get the VSEL value for the given voltage */
565 err = twl_vreg_millivolt_to_vsel(sc, regulator, millivolts, &vsel);
566 if (err)
567 return (err);
568
569 /* Need to upgrade because writing the voltage and enabling should be atomic */
570 xlocked = sx_xlocked(&sc->sc_sx);
571 if (!xlocked)
572 TWL_VREG_LOCK_UPGRADE(sc);
573
574 /* Set voltage and enable (atomically) */
575 err = twl_vreg_write_1(sc, regulator, TWL_VREG_VSEL, (vsel & 0x1f));
576 if (!err) {
577 err = twl_vreg_enable_regulator(sc, regulator);
578 }
579
580 if (!xlocked)
581 TWL_VREG_LOCK_DOWNGRADE(sc);
582
583 if ((twl_vreg_debug > 1) && !err)
584 device_printf(sc->sc_dev, "%s : setting voltage to %dmV (vsel: 0x%x)\n",
585 regulator->name, millivolts, vsel);
586
587 return (err);
588 }
589
590 /**
591 * twl_vreg_read_regulator_voltage - reads the voltage on a given regulator
592 * @sc: the device soft context
593 * @regulator: pointer to the regulator structure
594 * @millivolts: upon return will contain the voltage on the regulator
595 *
596 * LOCKING:
597 * On entry expects the TWL VREG lock to be held. It will upgrade the lock to
598 * exclusive if not already, but if so, it will be downgraded again before
599 * returning.
600 *
601 * RETURNS:
602 * Zero on success, or otherwise an error code.
603 */
604 static int
twl_vreg_read_regulator_voltage(struct twl_vreg_softc * sc,struct twl_regulator_entry * regulator,int * millivolts)605 twl_vreg_read_regulator_voltage(struct twl_vreg_softc *sc,
606 struct twl_regulator_entry *regulator, int *millivolts)
607 {
608 int err;
609 int en = 0;
610 int xlocked;
611 uint8_t vsel;
612
613 TWL_VREG_ASSERT_LOCKED(sc);
614
615 /* Need to upgrade the lock because checking enabled state and voltage
616 * should be atomic.
617 */
618 xlocked = sx_xlocked(&sc->sc_sx);
619 if (!xlocked)
620 TWL_VREG_LOCK_UPGRADE(sc);
621
622 /* Check if the regulator is currently enabled */
623 err = twl_vreg_is_regulator_enabled(sc, regulator, &en);
624 if (err)
625 goto done;
626
627 *millivolts = 0;
628 if (!en)
629 goto done;
630
631 /* Not all voltages are adjustable */
632 if (regulator->supp_voltages == NULL || !regulator->num_supp_voltages) {
633 *millivolts = regulator->fixed_voltage;
634 goto done;
635 }
636
637 /* For variable voltages read the voltage register */
638 err = twl_vreg_read_1(sc, regulator, TWL_VREG_VSEL, &vsel);
639 if (err)
640 goto done;
641
642 vsel &= (regulator->num_supp_voltages - 1);
643 if (regulator->supp_voltages[vsel] == UNDF) {
644 err = EINVAL;
645 goto done;
646 }
647
648 *millivolts = regulator->supp_voltages[vsel];
649
650 done:
651 if (!xlocked)
652 TWL_VREG_LOCK_DOWNGRADE(sc);
653
654 if ((twl_vreg_debug > 1) && !err)
655 device_printf(sc->sc_dev, "%s : reading voltage is %dmV (vsel: 0x%x)\n",
656 regulator->name, *millivolts, vsel);
657
658 return (err);
659 }
660
661 /**
662 * twl_vreg_get_voltage - public interface to read the voltage on a regulator
663 * @dev: TWL VREG device
664 * @name: the name of the regulator to read the voltage of
665 * @millivolts: pointer to an integer that upon return will contain the mV
666 *
667 * If the regulator is disabled the function will set the @millivolts to zero.
668 *
669 * LOCKING:
670 * Internally the function takes and releases the TWL VREG lock.
671 *
672 * RETURNS:
673 * Zero on success or a negative error code on failure.
674 */
675 int
twl_vreg_get_voltage(device_t dev,const char * name,int * millivolts)676 twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts)
677 {
678 struct twl_vreg_softc *sc;
679 struct twl_regulator_entry *regulator;
680 int err = EINVAL;
681
682 if (millivolts == NULL)
683 return (EINVAL);
684
685 sc = device_get_softc(dev);
686
687 TWL_VREG_SLOCK(sc);
688
689 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
690 if (strcmp(regulator->name, name) == 0) {
691 err = twl_vreg_read_regulator_voltage(sc, regulator, millivolts);
692 break;
693 }
694 }
695
696 TWL_VREG_SUNLOCK(sc);
697
698 return (err);
699 }
700
701 /**
702 * twl_vreg_set_voltage - public interface to write the voltage on a regulator
703 * @dev: TWL VREG device
704 * @name: the name of the regulator to read the voltage of
705 * @millivolts: the voltage to set in millivolts
706 *
707 * Sets the output voltage on a given regulator. If the regulator is a fixed
708 * voltage reg then the @millivolts value should match the fixed voltage. If
709 * a variable regulator then the @millivolt value must fit within the max/min
710 * range of the given regulator.
711 *
712 * LOCKING:
713 * Internally the function takes and releases the TWL VREG lock.
714 *
715 * RETURNS:
716 * Zero on success or a negative error code on failure.
717 */
718 int
twl_vreg_set_voltage(device_t dev,const char * name,int millivolts)719 twl_vreg_set_voltage(device_t dev, const char *name, int millivolts)
720 {
721 struct twl_vreg_softc *sc;
722 struct twl_regulator_entry *regulator;
723 int err = EINVAL;
724
725 sc = device_get_softc(dev);
726
727 TWL_VREG_SLOCK(sc);
728
729 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
730 if (strcmp(regulator->name, name) == 0) {
731 err = twl_vreg_write_regulator_voltage(sc, regulator, millivolts);
732 break;
733 }
734 }
735
736 TWL_VREG_SUNLOCK(sc);
737
738 return (err);
739 }
740
741 /**
742 * twl_sysctl_voltage - reads or writes the voltage for a regulator
743 * @SYSCTL_HANDLER_ARGS: arguments for the callback
744 *
745 * Callback for the sysctl entry for the regulator, simply used to return
746 * the voltage on a particular regulator.
747 *
748 * LOCKING:
749 * Takes the TWL_VREG shared lock internally.
750 *
751 * RETURNS:
752 * Zero on success or an error code on failure.
753 */
754 static int
twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS)755 twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS)
756 {
757 struct twl_vreg_softc *sc = (struct twl_vreg_softc*)arg1;
758 struct twl_regulator_entry *regulator;
759 int voltage;
760 int found = 0;
761
762 TWL_VREG_SLOCK(sc);
763
764 /* Find the regulator with the matching name */
765 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
766 if (strcmp(regulator->name, oidp->oid_name) == 0) {
767 found = 1;
768 break;
769 }
770 }
771
772 /* Sanity check that we found the regulator */
773 if (!found) {
774 TWL_VREG_SUNLOCK(sc);
775 return (EINVAL);
776 }
777
778 twl_vreg_read_regulator_voltage(sc, regulator, &voltage);
779
780 TWL_VREG_SUNLOCK(sc);
781
782 return sysctl_handle_int(oidp, &voltage, 0, req);
783 }
784
785 /**
786 * twl_add_regulator - adds single voltage regulator sysctls for the device
787 * @sc: device soft context
788 * @name: the name of the regulator
789 * @nsub: the number of the subdevice
790 * @regbase: the base address of the voltage regulator registers
791 * @fixed_voltage: if a fixed voltage regulator this defines it's voltage
792 * @voltages: if a variable voltage regulator, an array of possible voltages
793 * @num_voltages: the number of entries @voltages
794 *
795 * Adds a voltage regulator to the device and also a sysctl interface for the
796 * regulator.
797 *
798 * LOCKING:
799 * The TWL_VEG exclusive lock must be held while this function is called.
800 *
801 * RETURNS:
802 * Pointer to the new regulator entry on success, otherwise on failure NULL.
803 */
804 static struct twl_regulator_entry*
twl_vreg_add_regulator(struct twl_vreg_softc * sc,const char * name,uint8_t nsub,uint8_t regbase,uint16_t fixed_voltage,const uint16_t * voltages,uint32_t num_voltages)805 twl_vreg_add_regulator(struct twl_vreg_softc *sc, const char *name,
806 uint8_t nsub, uint8_t regbase, uint16_t fixed_voltage,
807 const uint16_t *voltages, uint32_t num_voltages)
808 {
809 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
810 struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
811 struct twl_regulator_entry *new;
812
813 new = malloc(sizeof(struct twl_regulator_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
814 if (new == NULL)
815 return (NULL);
816
817 strncpy(new->name, name, TWL_VREG_MAX_NAMELEN);
818 new->name[TWL_VREG_MAX_NAMELEN - 1] = '\0';
819
820 new->sub_dev = nsub;
821 new->reg_off = regbase;
822
823 new->fixed_voltage = fixed_voltage;
824
825 new->supp_voltages = voltages;
826 new->num_supp_voltages = num_voltages;
827
828 /* Add a sysctl entry for the voltage */
829 new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
830 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
831 twl_vreg_sysctl_voltage, "I", "voltage regulator");
832
833 /* Finally add the regulator to list of supported regulators */
834 LIST_INSERT_HEAD(&sc->sc_vreg_list, new, entries);
835
836 return (new);
837 }
838
839 /**
840 * twl_vreg_add_regulators - adds any voltage regulators to the device
841 * @sc: device soft context
842 * @chip: the name of the chip used in the hints
843 * @regulators: the list of possible voltage regulators
844 *
845 * Loops over the list of regulators and matches up with the FDT values,
846 * adjusting the actual voltage based on the supplied values.
847 *
848 * LOCKING:
849 * The TWL_VEG exclusive lock must be held while this function is called.
850 *
851 * RETURNS:
852 * Always returns 0.
853 */
854 static int
twl_vreg_add_regulators(struct twl_vreg_softc * sc,const struct twl_regulator * regulators)855 twl_vreg_add_regulators(struct twl_vreg_softc *sc,
856 const struct twl_regulator *regulators)
857 {
858 int err;
859 int millivolts;
860 const struct twl_regulator *walker;
861 struct twl_regulator_entry *entry;
862 phandle_t child;
863 char rnames[256];
864 char *name, *voltage;
865 int len = 0, prop_len;
866
867 /* Add the regulators from the list */
868 walker = ®ulators[0];
869 while (walker->name != NULL) {
870 /* Add the regulator to the list */
871 entry = twl_vreg_add_regulator(sc, walker->name, walker->subdev,
872 walker->regbase, walker->fixedvoltage,
873 walker->voltages, walker->num_voltages);
874 if (entry == NULL)
875 continue;
876
877 walker++;
878 }
879
880 /* Check if the FDT is telling us to set any voltages */
881 child = ofw_bus_get_node(sc->sc_pdev);
882 if (child) {
883 prop_len = OF_getprop(child, "voltage-regulators", rnames, sizeof(rnames));
884 while (len < prop_len) {
885 name = rnames + len;
886 len += strlen(name) + 1;
887 if ((len >= prop_len) || (name[0] == '\0'))
888 break;
889
890 voltage = rnames + len;
891 len += strlen(voltage) + 1;
892 if (voltage[0] == '\0')
893 break;
894
895 millivolts = strtoul(voltage, NULL, 0);
896
897 LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
898 if (strcmp(entry->name, name) == 0) {
899 twl_vreg_write_regulator_voltage(sc, entry, millivolts);
900 break;
901 }
902 }
903 }
904 }
905
906 if (twl_vreg_debug) {
907 LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
908 err = twl_vreg_read_regulator_voltage(sc, entry, &millivolts);
909 if (!err)
910 device_printf(sc->sc_dev, "%s : %d mV\n", entry->name, millivolts);
911 }
912 }
913
914 return (0);
915 }
916
917 /**
918 * twl_vreg_init - initialises the list of regulators
919 * @dev: the twl_vreg device
920 *
921 * This function is called as an intrhook once interrupts have been enabled,
922 * this is done so that the driver has the option to enable/disable or set
923 * the voltage level based on settings providied in the FDT.
924 *
925 * LOCKING:
926 * Takes the exclusive lock in the function.
927 */
928 static void
twl_vreg_init(void * dev)929 twl_vreg_init(void *dev)
930 {
931 struct twl_vreg_softc *sc;
932
933 sc = device_get_softc((device_t)dev);
934
935 TWL_VREG_XLOCK(sc);
936
937 if (twl_is_4030(sc->sc_pdev))
938 twl_vreg_add_regulators(sc, twl4030_regulators);
939 else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
940 twl_vreg_add_regulators(sc, twl6030_regulators);
941
942 TWL_VREG_XUNLOCK(sc);
943
944 config_intrhook_disestablish(&sc->sc_init_hook);
945 }
946
947 static int
twl_vreg_probe(device_t dev)948 twl_vreg_probe(device_t dev)
949 {
950 if (twl_is_4030(device_get_parent(dev)))
951 device_set_desc(dev, "TI TWL4030 PMIC Voltage Regulators");
952 else if (twl_is_6025(device_get_parent(dev)) ||
953 twl_is_6030(device_get_parent(dev)))
954 device_set_desc(dev, "TI TWL6025/TWL6030 PMIC Voltage Regulators");
955 else
956 return (ENXIO);
957
958 return (0);
959 }
960
961 static int
twl_vreg_attach(device_t dev)962 twl_vreg_attach(device_t dev)
963 {
964 struct twl_vreg_softc *sc;
965
966 sc = device_get_softc(dev);
967 sc->sc_dev = dev;
968 sc->sc_pdev = device_get_parent(dev);
969
970 TWL_VREG_LOCK_INIT(sc);
971
972 LIST_INIT(&sc->sc_vreg_list);
973
974 /* We have to wait until interrupts are enabled. I2C read and write
975 * only works if the interrupts are available.
976 */
977 sc->sc_init_hook.ich_func = twl_vreg_init;
978 sc->sc_init_hook.ich_arg = dev;
979
980 if (config_intrhook_establish(&sc->sc_init_hook) != 0)
981 return (ENOMEM);
982
983 return (0);
984 }
985
986 static int
twl_vreg_detach(device_t dev)987 twl_vreg_detach(device_t dev)
988 {
989 struct twl_vreg_softc *sc;
990 struct twl_regulator_entry *regulator;
991 struct twl_regulator_entry *tmp;
992
993 sc = device_get_softc(dev);
994
995 /* Take the lock and free all the added regulators */
996 TWL_VREG_XLOCK(sc);
997
998 LIST_FOREACH_SAFE(regulator, &sc->sc_vreg_list, entries, tmp) {
999 LIST_REMOVE(regulator, entries);
1000 sysctl_remove_oid(regulator->oid, 1, 0);
1001 free(regulator, M_DEVBUF);
1002 }
1003
1004 TWL_VREG_XUNLOCK(sc);
1005
1006 TWL_VREG_LOCK_DESTROY(sc);
1007
1008 return (0);
1009 }
1010
1011 static device_method_t twl_vreg_methods[] = {
1012 DEVMETHOD(device_probe, twl_vreg_probe),
1013 DEVMETHOD(device_attach, twl_vreg_attach),
1014 DEVMETHOD(device_detach, twl_vreg_detach),
1015
1016 {0, 0},
1017 };
1018
1019 static driver_t twl_vreg_driver = {
1020 "twl_vreg",
1021 twl_vreg_methods,
1022 sizeof(struct twl_vreg_softc),
1023 };
1024
1025 DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, 0, 0);
1026 MODULE_VERSION(twl_vreg, 1);
1027