xref: /netbsd-src/sys/dev/i2c/tps65217pmic.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: tps65217pmic.c,v 1.12 2018/06/16 21:22:13 thorpej Exp $ */
2 
3 /*-
4  * Copyright (c) 2013 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Radoslaw Kujawa.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Texas Instruments TPS65217 Power Management IC driver.
34  * TODO: battery, sequencer, pgood
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: tps65217pmic.c,v 1.12 2018/06/16 21:22:13 thorpej Exp $");
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/device.h>
43 #include <sys/kernel.h>
44 #include <sys/mutex.h>
45 
46 #include <sys/bus.h>
47 #include <dev/i2c/i2cvar.h>
48 
49 #include <dev/sysmon/sysmonvar.h>
50 
51 #include <dev/i2c/tps65217pmicreg.h>
52 #include <dev/i2c/tps65217pmicvar.h>
53 
54 #define NTPS_REG	7
55 #define SNUM_REGS	NTPS_REG-1
56 #define SNUM_USBSTATUS	NTPS_REG
57 #define SNUM_ACSTATUS	NTPS_REG+1
58 
59 struct tps65217pmic_softc {
60 	device_t		sc_dev;
61 
62 	i2c_tag_t		sc_tag;
63 	i2c_addr_t		sc_addr;
64 
65 	uint8_t			sc_version;
66 	uint8_t			sc_revision;
67 
68 	kmutex_t		sc_lock;
69 
70 	bool			sc_acstatus;
71 	bool			sc_usbstatus;
72 	bool			sc_acenabled;
73 	bool			sc_usbenabled;
74 
75 	callout_t		sc_powerpollco;
76 
77 	/* sysmon(4) stuff */
78 	struct sysmon_envsys	*sc_sme;
79 	envsys_data_t		sc_regsensor[NTPS_REG];
80 	envsys_data_t		sc_acsensor;
81 	envsys_data_t		sc_usbsensor;
82 
83 	struct sysmon_pswitch	sc_smpsw;
84 };
85 
86 /* Voltage regulators */
87 enum tps_reg_num {
88 	TPS65217PMIC_LDO1,
89 	TPS65217PMIC_LDO2,
90 	TPS65217PMIC_LDO3LS,
91 	TPS65217PMIC_LDO4LS,
92 	TPS65217PMIC_DCDC1,
93 	TPS65217PMIC_DCDC2,
94 	TPS65217PMIC_DCDC3
95 };
96 
97 struct tps_reg_param {
98 	/* parameters configured statically */
99 
100 	const char* name;
101 	uint16_t voltage_min;		/* in mV */
102 	uint16_t voltage_max;		/* in mV */
103 	const uint16_t *voltages;	/* all possible voltage settings */
104 	uint8_t nvoltages;		/* number of voltage settings */
105 
106 	bool can_track;			/* regulator can track U of other r. */
107 	struct tps_reg_param *tracked_reg; /* ptr to tracked regulator */
108 	bool can_xadj;			/* voltage can be adjusted externally */
109 	bool can_ls;			/* can be a load switch instead of r. */
110 
111 	uint8_t defreg_num;		/* DEF register */
112 	uint8_t enable_bit;		/* position in ENABLE register */
113 
114 	/*
115 	 * Run-time parameters configured during attachment and later, these
116 	 * probably should be split into separate struct that would be a part
117 	 * of softc. But since we can have only one TPS chip, that should be
118 	 * okay for now.
119 	 */
120 
121 	bool is_enabled;		/* regulator is enabled */
122 	bool is_pg;			/* regulator is "power good" */
123 	bool is_tracking;		/* voltage is tracking other reg. */
124 	bool is_ls;			/* is a load switch */
125 	bool is_xadj;			/* voltage is adjusted externally */
126 
127 	uint16_t current_voltage;	/* in mV */
128 
129 };
130 
131 static int tps65217pmic_match(device_t, cfdata_t, void *);
132 static void tps65217pmic_attach(device_t, device_t, void *);
133 
134 static uint8_t tps65217pmic_reg_read(struct tps65217pmic_softc *, uint8_t);
135 static void tps65217pmic_reg_write(struct tps65217pmic_softc *, uint8_t,
136     uint8_t);
137 
138 static void tps65217pmic_reg_refresh(struct tps65217pmic_softc *);
139 
140 static uint16_t tps65217pmic_ppath_max_usb_current(uint8_t);
141 static uint16_t tps65217pmic_ppath_max_ac_current(uint8_t);
142 
143 static void tps65217pmic_regulator_read_config(struct tps65217pmic_softc *,
144     struct tps_reg_param *);
145 
146 static void tps65217pmic_print_ppath(struct tps65217pmic_softc *);
147 static void tps65217pmic_print_ldos(struct tps65217pmic_softc *);
148 
149 static void tps65217pmic_version(struct tps65217pmic_softc *);
150 
151 static void tps65217pmic_envsys_register(struct tps65217pmic_softc *);
152 static void tps65217pmic_envsys_refresh(struct sysmon_envsys *, envsys_data_t *);
153 
154 static void tps65217pmic_power_monitor_init(struct tps65217pmic_softc *);
155 static void tps65217pmic_power_monitor(void *);
156 
157 static void tps65217pmic_wled_init(struct tps65217pmic_softc *, int, int, int);
158 
159 CFATTACH_DECL_NEW(tps65217pmic, sizeof (struct tps65217pmic_softc),
160     tps65217pmic_match, tps65217pmic_attach, NULL, NULL);
161 
162 /* Possible settings of LDO1 in mV. */
163 static const uint16_t ldo1voltages[] = { 1000, 1100, 1200, 1250, 1300, 1350,
164     1400, 1500, 1600, 1800, 2500, 2750, 2800, 3000, 3100, 3300 };
165 /* Possible settings of LDO2, DCDC1, DCDC2, DCDC3 in mV. */
166 static const uint16_t ldo2voltages[] = { 900, 925, 950, 975, 1000, 1025, 1050,
167     1075, 1100, 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, 1325, 1350,
168     1375, 1400, 1425, 1450, 1475, 1500, 1550, 1600, 1650, 1700, 1750, 1800,
169     1850, 1900, 1950, 2000, 2050, 2100, 2150, 2200, 2250, 2300, 2350, 2400,
170     2450, 2500, 2550, 2600, 2650, 2700, 2750, 2800, 2850, 2900, 3000, 3100,
171     3200, 3300, 3300, 3300, 3300, 3300, 3300, 3300, 3300 };
172 /* Possible settings of LDO3, LDO4 in mV. */
173 static const uint16_t ldo3voltages[] = { 1500, 1550, 1600, 1650, 1700, 1750,
174     1800, 1850, 1900, 2000, 2100, 2200, 2300, 2400, 2450, 2500, 2550, 2600,
175     2650, 2700, 2750, 2800, 2850, 2900,2950, 3000, 3050, 3100, 3150, 3200,
176     3250, 3300 };
177 
178 static struct tps_reg_param tps_regulators[] = {
179 	{
180 		.name = "LDO1",
181 		.voltage_min = 1000,
182 		.voltage_max = 3300,
183 		.voltages = ldo1voltages,
184 		.nvoltages = 16,
185 		.can_track = false,
186 		.tracked_reg = NULL,
187 		.can_xadj =  false,
188 		.can_ls = false,
189 		.defreg_num = TPS65217PMIC_DEFLDO1,
190 		.enable_bit = TPS65217PMIC_ENABLE_LDO1
191 	},
192 	{
193 		.name = "LDO2",
194 		.voltage_min = 900,
195 		.voltage_max = 3300,
196 		.voltages = ldo2voltages,
197 		.nvoltages = 64,
198 		.can_track = true,
199 		.tracked_reg = &(tps_regulators[TPS65217PMIC_DCDC3]),
200 		.can_xadj = false,
201 		.can_ls = false,
202 		.defreg_num = TPS65217PMIC_DEFLDO2,
203 		.enable_bit = TPS65217PMIC_ENABLE_LDO2
204 	},
205 	{
206 		.name = "LDO3",
207 		.voltage_min = 1500,
208 		.voltage_max = 3300,
209 		.voltages = ldo3voltages,
210 		.nvoltages = 32,
211 		.can_track = false,
212 		.tracked_reg = NULL,
213 		.can_xadj = false,
214 		.can_ls = true,
215 		.defreg_num = TPS65217PMIC_DEFLDO3,
216 		.enable_bit = TPS65217PMIC_ENABLE_LDO3
217 	},
218 	{
219 		.name = "LDO4",
220 		.voltage_min = 1500,
221 		.voltage_max = 3300,
222 		.voltages = ldo3voltages,
223 		.nvoltages = 32,
224 		.can_track = false,
225 		.tracked_reg = NULL,
226 		.can_xadj = false,
227 		.can_ls = true,
228 		.defreg_num = TPS65217PMIC_DEFLDO4,
229 		.enable_bit = TPS65217PMIC_ENABLE_LDO4
230 	},
231 	{
232 		.name = "DCDC1",
233 		.voltage_min = 900,
234 		.voltage_max = 3300,
235 		.voltages = ldo2voltages,
236 		.nvoltages = 64,
237 		.can_track = false,
238 		.tracked_reg = NULL,
239 		.can_xadj = true,
240 		.can_ls = false,
241 		.defreg_num = TPS65217PMIC_DEFDCDC1,
242 		.enable_bit = TPS65217PMIC_ENABLE_DCDC1
243 	},
244 	{
245 		.name = "DCDC2",
246 		.voltage_min = 900,
247 		.voltage_max = 3300,
248 		.voltages = ldo2voltages,
249 		.nvoltages = 64,
250 		.can_track = false,
251 		.tracked_reg = NULL,
252 		.can_xadj = true,
253 		.can_ls = false,
254 		.defreg_num = TPS65217PMIC_DEFDCDC2,
255 		.enable_bit = TPS65217PMIC_ENABLE_DCDC2
256 	},
257 	{
258 		.name = "DCDC3",
259 		.voltage_min = 900,
260 		.voltage_max = 3300,
261 		.voltages = ldo2voltages,
262 		.nvoltages = 64,
263 		.can_track = false,
264 		.tracked_reg = NULL,
265 		.can_xadj = true,
266 		.can_ls = false,
267 		.defreg_num = TPS65217PMIC_DEFDCDC3,
268 		.enable_bit = TPS65217PMIC_ENABLE_DCDC3
269 	}
270 };
271 
272 static bool matched = false;
273 
274 static int
275 tps65217pmic_match(device_t parent, cfdata_t cf, void *aux)
276 {
277 	struct i2c_attach_args *ia = aux;
278 
279 	if (ia->ia_addr == TPS65217PMIC_ADDR) {
280 		/* we can only have one */
281 		if (matched)
282 			return 0;
283 
284 		return I2C_MATCH_ADDRESS_ONLY;
285 	}
286 	return 0;
287 }
288 
289 static void
290 tps65217pmic_attach(device_t parent, device_t self, void *aux)
291 {
292 	struct tps65217pmic_softc *sc = device_private(self);
293 	struct i2c_attach_args *ia = aux;
294 	prop_dictionary_t dict;
295 	int isel, fdim, brightness;
296 
297 	/* XXXJRT But what if you have multiple i2c busses? */
298 	matched = true;
299 
300 	sc->sc_dev = self;
301 	sc->sc_addr = ia->ia_addr;
302 	sc->sc_tag = ia->ia_tag;
303 
304 	dict = device_properties(self);
305 	if (prop_dictionary_get_int32(dict, "isel", &isel)) {
306 		prop_dictionary_get_int32(dict, "fdim", &fdim);
307 		prop_dictionary_get_int32(dict, "brightness", &brightness);
308 	} else
309 		isel = -1;
310 
311 	tps65217pmic_version(sc);
312 
313 	aprint_normal(": TPS65217");
314 	switch (sc->sc_version) {
315 	case TPS65217PMIC_CHIPID_VER_A:
316 		aprint_normal("A");
317 		break;
318 	case TPS65217PMIC_CHIPID_VER_B:
319 		aprint_normal("B");
320 		break;
321 	case TPS65217PMIC_CHIPID_VER_C:
322 		aprint_normal("C");
323 		break;
324 	case TPS65217PMIC_CHIPID_VER_D:
325 		aprint_normal("D");
326 		break;
327 	default:
328 		/* unknown version */
329 		break;
330 	}
331 
332 	aprint_normal(" Power Management Multi-Channel IC (rev 1.%d)\n",
333 	    sc->sc_revision);
334 
335 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
336 
337 	sc->sc_smpsw.smpsw_name = device_xname(self);
338 	sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_ACADAPTER;
339 	sysmon_pswitch_register(&sc->sc_smpsw);
340 
341 	tps65217pmic_reg_refresh(sc);
342 
343 	tps65217pmic_print_ppath(sc);
344 	tps65217pmic_print_ldos(sc);
345 
346 	tps65217pmic_power_monitor_init(sc);
347 
348 	if (isel != -1)
349 		tps65217pmic_wled_init(sc, isel, fdim, brightness);
350 
351 	tps65217pmic_envsys_register(sc);
352 }
353 
354 static void
355 tps65217pmic_power_monitor_init(struct tps65217pmic_softc *sc)
356 {
357 	uint8_t intr, intrmask, status, ppath;
358 
359 	intrmask = TPS65217PMIC_INT_USBM | TPS65217PMIC_INT_ACM |
360 	    TPS65217PMIC_INT_PBM;
361 
362 	status = tps65217pmic_reg_read(sc, TPS65217PMIC_STATUS);
363 	ppath = tps65217pmic_reg_read(sc, TPS65217PMIC_PPATH);
364 	/* acknowledge and disregard whatever interrupt was generated earlier */
365 	intr = tps65217pmic_reg_read(sc, TPS65217PMIC_INT);
366 
367 	sc->sc_usbstatus = status & TPS65217PMIC_STATUS_USBPWR;
368 	sc->sc_acstatus = status & TPS65217PMIC_STATUS_ACPWR;
369 	sc->sc_usbenabled = ppath & TPS65217PMIC_PPATH_USB_EN;
370 	sc->sc_acenabled = ppath & TPS65217PMIC_PPATH_AC_EN;
371 
372 	if (intr & intrmask)
373 		aprint_normal_dev(sc->sc_dev,
374 		    "WARNING: hardware interrupt enabled but not supported");
375 
376 	/* set up callout to poll for power source changes */
377 	callout_init(&sc->sc_powerpollco, 0);
378 	callout_setfunc(&sc->sc_powerpollco, tps65217pmic_power_monitor, sc);
379 
380 	callout_schedule(&sc->sc_powerpollco, hz);
381 }
382 
383 static void
384 tps65217pmic_power_monitor(void *aux)
385 {
386 	struct tps65217pmic_softc *sc;
387 	uint8_t status;
388 	bool usbstatus, acstatus;
389 
390 	sc = aux;
391 
392 	mutex_enter(&sc->sc_lock);
393 
394 	status = tps65217pmic_reg_read(sc, TPS65217PMIC_STATUS);
395 	usbstatus = status & TPS65217PMIC_STATUS_USBPWR;
396 	acstatus = status & TPS65217PMIC_STATUS_ACPWR;
397 
398 	if (usbstatus != sc->sc_usbstatus) {
399 		sc->sc_usbstatus = usbstatus;
400 		pmf_event_inject(NULL, PMFE_POWER_CHANGED);
401 		if (usbstatus)
402 			aprint_normal_dev(sc->sc_dev,
403 			    "USB power source connected\n");
404 		else
405 			aprint_normal_dev(sc->sc_dev,
406 			    "USB power source disconnected\n");
407 	}
408 
409 	if (acstatus != sc->sc_acstatus) {
410 		sc->sc_acstatus = acstatus;
411 		pmf_event_inject(NULL, PMFE_POWER_CHANGED);
412 		if (acstatus) {
413 			sysmon_pswitch_event(&sc->sc_smpsw,
414 			    PSWITCH_EVENT_PRESSED);
415 		} else {
416 			sysmon_pswitch_event(&sc->sc_smpsw,
417 			    PSWITCH_EVENT_RELEASED);
418 		}
419 	}
420 
421 	mutex_exit(&sc->sc_lock);
422 
423 	callout_schedule(&sc->sc_powerpollco, hz);
424 }
425 
426 static void
427 tps65217pmic_wled_init(struct tps65217pmic_softc *sc, int isel, int fdim,
428 		       int brightness)
429 {
430 	uint8_t val = 0;
431 
432 	switch (isel) {
433 	case 1:
434 	case 2:
435 		val |= ((isel - 1) << TPS65217PMIC_WLEDCTRL1_ISEL);
436 		break;
437 	default:
438 		aprint_error_dev(sc->sc_dev,
439 		    "WLED ISET selection is 1 or 2: isel %d\n", isel);
440 		return;
441 	}
442 	switch (fdim) {
443 	case 100:
444 		val |= TPS65217PMIC_WLEDCTRL1_FDIM_100Hz;
445 		break;
446 	case 200:
447 		val |= TPS65217PMIC_WLEDCTRL1_FDIM_200Hz;
448 		break;
449 	case 500:
450 		val |= TPS65217PMIC_WLEDCTRL1_FDIM_500Hz;
451 		break;
452 	case 1000:
453 		val |= TPS65217PMIC_WLEDCTRL1_FDIM_1000Hz;
454 		break;
455 	default:
456 		aprint_error_dev(sc->sc_dev,
457 		    "WLED PWM dimming frequency is 100, 200, 500 or 1000:"
458 		    " fdim %d\n", fdim);
459 		return;
460 	}
461 	if (brightness > 100 ||
462 	    brightness < 0) {
463 		aprint_error_dev(sc->sc_dev,
464 		    "invalid brightness: between 0 and 100: %d\n", brightness);
465 		return;
466 	}
467 
468 	tps65217pmic_reg_write(sc, TPS65217PMIC_WLEDCTRL1, val);
469 	tps65217pmic_reg_write(sc, TPS65217PMIC_WLEDCTRL2,
470 	    (brightness - 1) & TPS65217PMIC_WLEDCTRL2_DUTY);
471 	val |= TPS65217PMIC_WLEDCTRL1_ISINK_EN;
472 	tps65217pmic_reg_write(sc, TPS65217PMIC_WLEDCTRL1, val);
473 }
474 
475 static void
476 tps65217pmic_reg_refresh(struct tps65217pmic_softc *sc)
477 {
478 	int i;
479 	struct tps_reg_param *c_reg;
480 
481 	for (i = 0; i < NTPS_REG; i++) {
482 		c_reg = &tps_regulators[i];
483 		tps65217pmic_regulator_read_config(sc, c_reg);
484 	}
485 }
486 
487 /* Get version and revision of the chip. */
488 static void
489 tps65217pmic_version(struct tps65217pmic_softc *sc)
490 {
491 	uint8_t chipid;
492 
493 	chipid = tps65217pmic_reg_read(sc, TPS65217PMIC_CHIPID);
494 
495 	sc->sc_version = chipid & TPS65217PMIC_CHIPID_VER_MASK;
496 	sc->sc_revision = chipid & TPS65217PMIC_CHIPID_REV_MASK;
497 }
498 
499 static uint16_t
500 tps65217pmic_ppath_max_ac_current(uint8_t ppath)
501 {
502 	switch ((ppath & TPS65217PMIC_PPATH_IAC) >>
503 	    TPS65217PMIC_PPATH_IAC_RSHFIT) {
504 	case TPS65217PMIC_PPATH_IAC_100MA:
505 		return 100;
506 	case TPS65217PMIC_PPATH_IAC_500MA:
507 		return 500;
508 	case TPS65217PMIC_PPATH_IAC_1300MA:
509 		return 1300;
510 	case TPS65217PMIC_PPATH_IAC_2500MA:
511 		return 2500;
512 	}
513 	return 0;
514 }
515 
516 static uint16_t
517 tps65217pmic_ppath_max_usb_current(uint8_t ppath)
518 {
519 	switch (ppath & TPS65217PMIC_PPATH_IUSB) {
520 	case TPS65217PMIC_PPATH_IUSB_100MA:
521 		return 100;
522 	case TPS65217PMIC_PPATH_IUSB_500MA:
523 		return 500;
524 	case TPS65217PMIC_PPATH_IUSB_1300MA:
525 		return 1300;
526 	case TPS65217PMIC_PPATH_IUSB_1800MA:
527 		return 1800;
528 	}
529 	return 0;
530 }
531 
532 /* Read regulator state and save it to tps_reg_param. */
533 static void
534 tps65217pmic_regulator_read_config(struct tps65217pmic_softc *sc, struct
535     tps_reg_param *regulator)
536 {
537 	uint8_t defreg, regenable;
538 	uint16_t voltage;
539 
540 	regenable = tps65217pmic_reg_read(sc, TPS65217PMIC_ENABLE);
541 
542 	if (regenable & (regulator->enable_bit))
543 		regulator->is_enabled = true;
544 	else {
545 		regulator->is_enabled = false;
546 		return;
547 	}
548 
549 	defreg = tps65217pmic_reg_read(sc,
550 	    regulator->defreg_num);
551 
552 	switch (regulator->nvoltages) {
553 	case 16:
554 		voltage = regulator->voltages[defreg &
555 		    TPS65217PMIC_DEFX_VOLTAGE_16];
556 		break;
557 	case 32:
558 		voltage = regulator->voltages[defreg &
559 		    TPS65217PMIC_DEFX_VOLTAGE_32];
560 		break;
561 	case 64:
562 		voltage = regulator->voltages[defreg &
563 		    TPS65217PMIC_DEFX_VOLTAGE_64];
564 		break;
565 	default:
566 		/* unsupported number of voltage settings? */
567 		voltage = 0;
568 		break;
569 	}
570 
571 	/* Handle regulator tracking other regulator voltage. */
572 	if (regulator->can_track)
573 		if (defreg & TPS65217PMIC_DEFX_TRACKING) {
574 			regulator->is_tracking = true;
575 			voltage = 0; /* see regulator->tracked_reg */
576 		}
577 
578 	/* Handle regulator configured into load switch mode. */
579 	if (regulator->can_ls)
580 		if (!(defreg & TPS65217PMIC_DEFX_LS)) {
581 			regulator->is_ls = true;
582 			voltage = 0;
583 		}
584 
585 	if (regulator->can_xadj)
586 		if (defreg & TPS65217PMIC_DEFX_XADJ) {
587 			regulator->is_xadj = true;
588 			voltage = 0;
589 
590 		}
591 
592 	/* TODO: add PGOOD checking */
593 
594 	regulator->current_voltage = voltage;
595 }
596 
597 static void
598 tps65217pmic_print_ldos(struct tps65217pmic_softc *sc)
599 {
600 	int i;
601 	struct tps_reg_param *c_reg;
602 
603 	aprint_normal_dev(sc->sc_dev, "");
604 
605 	for (i = 0; i < NTPS_REG; i++) {
606 		c_reg = &tps_regulators[i];
607 
608 		if (c_reg->is_enabled) {
609 			if (c_reg->is_ls)
610 				aprint_normal("[%s: LS] ", c_reg->name);
611 			else if (c_reg->is_xadj)
612 				aprint_normal("[%s: XADJ] ", c_reg->name);
613 			else
614 				aprint_normal("[%s: %d mV] ", c_reg->name,
615 				    c_reg->current_voltage);
616 		}
617 	}
618 	aprint_normal("\n");
619 }
620 
621 static void
622 tps65217pmic_print_ppath(struct tps65217pmic_softc *sc)
623 {
624 	uint8_t status, ppath;
625 
626 	ppath = tps65217pmic_reg_read(sc, TPS65217PMIC_PPATH);
627 	status = tps65217pmic_reg_read(sc, TPS65217PMIC_STATUS);
628 
629 	aprint_normal_dev(sc->sc_dev, "power sources ");
630 
631 	if (ppath & TPS65217PMIC_PPATH_USB_EN) {
632 		if (status & TPS65217PMIC_STATUS_USBPWR)
633 			aprint_normal("[USB] ");
634 		else
635 			aprint_normal("USB ");
636 		aprint_normal("max %d mA, ",
637 		    tps65217pmic_ppath_max_usb_current(ppath));
638 	}
639 
640 	if (ppath & TPS65217PMIC_PPATH_AC_EN) {
641 		if (status & TPS65217PMIC_STATUS_ACPWR)
642 			aprint_normal("[AC] ");
643 		else
644 			aprint_normal("AC ");
645 		aprint_normal("max %d mA",
646 		    tps65217pmic_ppath_max_ac_current(ppath));
647 	}
648 
649 	aprint_normal("\n");
650 }
651 
652 static uint8_t
653 tps65217pmic_reg_read(struct tps65217pmic_softc *sc, uint8_t reg)
654 {
655 	uint8_t wbuf[2];
656 	uint8_t rv;
657 
658 	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
659 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for read\n");
660 		return 0;
661 	}
662 
663 	wbuf[0] = reg;
664 
665 	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, wbuf,
666 	    1, &rv, 1, I2C_F_POLL)) {
667 		aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
668 		iic_release_bus(sc->sc_tag, I2C_F_POLL);
669 		return 0;
670 	}
671 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
672 
673 	return rv;
674 }
675 
676 static void
677 tps65217pmic_reg_write_unlocked(struct tps65217pmic_softc *sc,
678     uint8_t reg, uint8_t data)
679 {
680 	uint8_t wbuf[2];
681 
682 	wbuf[0] = reg;
683 	wbuf[1] = data;
684 
685 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, NULL, 0,
686 	    wbuf, 2, I2C_F_POLL)) {
687 		aprint_error_dev(sc->sc_dev, "cannot execute I2C write\n");
688 	}
689 }
690 
691 static void __unused
692 tps65217pmic_reg_write(struct tps65217pmic_softc *sc, uint8_t reg, uint8_t data)
693 {
694 
695 	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
696 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
697 		return;
698 	}
699 
700 	tps65217pmic_reg_write_unlocked(sc, reg, data);
701 
702 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
703 }
704 
705 static void
706 tps65217pmic_reg_write_l2(struct tps65217pmic_softc *sc,
707     uint8_t reg, uint8_t data)
708 {
709 	uint8_t regpw = reg ^ TPS65217PMIC_PASSWORD_XOR;
710 	if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
711 		aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
712 		return;
713 	}
714 
715 	tps65217pmic_reg_write_unlocked(sc, TPS65217PMIC_PASSWORD, regpw);
716 	tps65217pmic_reg_write_unlocked(sc, reg, data);
717 	tps65217pmic_reg_write_unlocked(sc, TPS65217PMIC_PASSWORD, regpw);
718 	tps65217pmic_reg_write_unlocked(sc, reg, data);
719 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
720 }
721 
722 static void
723 tps65217pmic_envsys_register(struct tps65217pmic_softc *sc)
724 {
725 	int i;
726 
727 	sc->sc_sme = sysmon_envsys_create();
728 
729 	/* iterate over all regulators and attach them as sensors */
730 	for(i = 0; i <= SNUM_REGS; i++) {
731 		/* set name */
732 		strlcpy(sc->sc_regsensor[i].desc, tps_regulators[i].name,
733 		    sizeof(sc->sc_regsensor[i].desc));
734 		sc->sc_regsensor[i].units = ENVSYS_SVOLTS_DC;
735 		sc->sc_regsensor[i].state = ENVSYS_SINVALID;
736 
737 		if (sysmon_envsys_sensor_attach(sc->sc_sme,
738 		    &sc->sc_regsensor[i]))
739 			aprint_error_dev(sc->sc_dev,
740 			    "error attaching regulator sensor %d\n", i);
741 	}
742 
743 	/* attach power source indicators */
744 	strcpy(sc->sc_usbsensor.desc, "USB power source"); /* SNUM_USBSTATUS */
745 	sc->sc_usbsensor.units = ENVSYS_INDICATOR;
746 	sc->sc_usbsensor.state = ENVSYS_SINVALID;
747 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_usbsensor))
748 		aprint_error_dev(sc->sc_dev,
749 		    "error attaching USB power source sensor\n");
750 	strcpy(sc->sc_acsensor.desc, "AC power source"); /* SNUM_ACSTATUS */
751 	sc->sc_acsensor.units = ENVSYS_INDICATOR;
752 	sc->sc_acsensor.state = ENVSYS_SINVALID;
753 	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_acsensor))
754 		aprint_error_dev(sc->sc_dev,
755 		    "error attaching AC power source sensor\n");
756 
757 	/* register everything in sysmon */
758 	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
759 	sc->sc_sme->sme_cookie = sc;
760 	sc->sc_sme->sme_refresh = tps65217pmic_envsys_refresh;
761 
762 	if (sysmon_envsys_register(sc->sc_sme)) {
763 		aprint_error_dev(sc->sc_dev, "unable to register in sysmon\n");
764 		sysmon_envsys_destroy(sc->sc_sme);
765 	}
766 }
767 
768 static void
769 tps65217pmic_envsys_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
770 {
771 	struct tps65217pmic_softc *sc = sme->sme_cookie;
772 
773 	mutex_enter(&sc->sc_lock);
774 
775 	tps65217pmic_reg_refresh(sc);
776 
777 	if (edata->sensor <= SNUM_REGS) {
778 		/* TODO: handle special cases like LS, XADJ... */
779 		edata->value_cur = tps_regulators[edata->sensor].current_voltage * 1000;
780 		edata->state = ENVSYS_SVALID;
781 	} else if (edata->sensor == SNUM_USBSTATUS) {
782 		edata->value_cur = sc->sc_usbstatus && sc->sc_usbenabled;
783 		edata->state = ENVSYS_SVALID;
784 	} else if (edata->sensor == SNUM_ACSTATUS) {
785 		edata->value_cur = sc->sc_acstatus && sc->sc_acenabled;
786 		edata->state = ENVSYS_SVALID;
787 	} else
788 		aprint_error_dev(sc->sc_dev, "unknown sensor number\n");
789 
790 	mutex_exit(&sc->sc_lock);
791 }
792 
793 int
794 tps65217pmic_set_volt(device_t self, const char *name, int mvolt)
795 {
796 	int i;
797 	struct tps65217pmic_softc *sc = device_private(self);
798 	struct tps_reg_param *regulator = NULL;
799 	uint8_t val;
800 
801 	for (i = 0; i < __arraycount(tps_regulators); i++) {
802 		if (strcmp(name, tps_regulators[i].name) == 0) {
803 			regulator = &tps_regulators[i];
804 			break;
805 		}
806 	}
807 	if (regulator == NULL)
808 		return EINVAL;
809 
810 	if (regulator->voltage_min > mvolt || regulator->voltage_max < mvolt)
811 		return EINVAL;
812 
813 	if (!regulator->is_enabled)
814 		return EINVAL;
815 
816 	if (regulator->is_tracking)
817 		return EINVAL;
818 
819 	if (regulator->is_xadj)
820 		return EINVAL;
821 
822 	/* find closest voltage entry */
823 	for (i = 0; i < regulator->nvoltages; i++) {
824 		if (mvolt <= regulator->voltages[i]) {
825 			break;
826 		}
827 	}
828 	KASSERT(i < regulator->nvoltages);
829 	tps65217pmic_reg_write_l2(sc, regulator->defreg_num, i);
830 
831 	val = tps65217pmic_reg_read(sc, TPS65217PMIC_DEFSLEW);
832 	val |= TPS65217PMIC_DEFSLEW_GO;
833 	tps65217pmic_reg_write_l2(sc, TPS65217PMIC_DEFSLEW, val);
834 
835 	while (val & TPS65217PMIC_DEFSLEW_GO) {
836 		val = tps65217pmic_reg_read(sc, TPS65217PMIC_DEFSLEW);
837 	}
838 	return 0;
839 }
840