xref: /openbsd-src/sys/dev/acpi/tipmic.c (revision c67891609a4faadaa2006b7ed8a6ab2ce32358a7)
1*c6789160Sdlg /*	$OpenBSD: tipmic.c,v 1.8 2023/03/04 01:23:40 dlg Exp $	*/
2ad7ce60aSkettenis /*
3ad7ce60aSkettenis  * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
4ad7ce60aSkettenis  *
5ad7ce60aSkettenis  * Permission to use, copy, modify, and distribute this software for any
6ad7ce60aSkettenis  * purpose with or without fee is hereby granted, provided that the above
7ad7ce60aSkettenis  * copyright notice and this permission notice appear in all copies.
8ad7ce60aSkettenis  *
9ad7ce60aSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10ad7ce60aSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ad7ce60aSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12ad7ce60aSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ad7ce60aSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ad7ce60aSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15ad7ce60aSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16ad7ce60aSkettenis  */
17ad7ce60aSkettenis 
18ad7ce60aSkettenis #include <sys/param.h>
19ad7ce60aSkettenis #include <sys/systm.h>
20ad7ce60aSkettenis #include <sys/device.h>
21ad7ce60aSkettenis #include <sys/kernel.h>
22ad7ce60aSkettenis #include <sys/malloc.h>
23ad7ce60aSkettenis 
24ad7ce60aSkettenis #include <dev/acpi/acpireg.h>
25ad7ce60aSkettenis #include <dev/acpi/acpivar.h>
26ad7ce60aSkettenis #include <dev/acpi/acpidev.h>
27ad7ce60aSkettenis #include <dev/acpi/amltypes.h>
28ad7ce60aSkettenis #include <dev/acpi/dsdt.h>
29ad7ce60aSkettenis 
30ad7ce60aSkettenis #include <dev/i2c/i2cvar.h>
31ad7ce60aSkettenis 
32ad7ce60aSkettenis #define TIPMIC_INTR_STAT		0x01
33ad7ce60aSkettenis #define  TIPMIC_INTR_STAT_ADC		(1 << 2)
34ad7ce60aSkettenis #define TIPMIC_INTR_MASK		0x02
35ad7ce60aSkettenis #define  TIPMIC_INTR_MASK_ADC		(1 << 2)
36ad7ce60aSkettenis #define  TIPMIC_INTR_MASK_ALL		0xff
37237e378aSkettenis #define TIPMIC_LDO1_CTRL		0x41
38237e378aSkettenis #define TIPMIC_LDO2_CTRL		0x42
39237e378aSkettenis #define TIPMIC_LDO3_CTRL		0x43
40237e378aSkettenis #define TIPMIC_LDO5_CTRL		0x45
41237e378aSkettenis #define TIPMIC_LDO6_CTRL		0x46
42237e378aSkettenis #define TIPMIC_LDO7_CTRL		0x47
43237e378aSkettenis #define TIPMIC_LDO8_CTRL		0x48
44237e378aSkettenis #define TIPMIC_LDO9_CTRL		0x49
45237e378aSkettenis #define TIPMIC_LDO10_CTRL		0x4a
46237e378aSkettenis #define TIPMIC_LDO11_CTRL		0x4b
47237e378aSkettenis #define TIPMIC_LDO12_CTRL		0x4c
48237e378aSkettenis #define TIPMIC_LDO13_CTRL		0x4d
49237e378aSkettenis #define TIPMIC_LDO14_CTRL		0x4e
50ad7ce60aSkettenis #define TIPMIC_ADC_CTRL			0x50
51ad7ce60aSkettenis #define  TIPMIC_ADC_CTRL_START		(1 << 0)
52ad7ce60aSkettenis #define  TIPMIC_ADC_CTRL_CH_MASK	(3 << 1)
53ad7ce60aSkettenis #define  TIPMIC_ADC_CTRL_CH_PMICTEMP	(1 << 1)
54ad7ce60aSkettenis #define  TIPMIC_ADC_CTRL_CH_BATTEMP	(2 << 1)
55ad7ce60aSkettenis #define  TIPMIC_ADC_CTRL_CH_SYSTEMP	(3 << 1)
56ad7ce60aSkettenis #define  TIPMIC_ADC_CTRL_EN		(1 << 5)
57ad7ce60aSkettenis #define TIPMIC_PMICTEMP_HI		0x56
58ad7ce60aSkettenis #define TIPMIC_PMICTEMP_LO		0x57
59ad7ce60aSkettenis #define TIPMIC_BATTEMP_HI		0x58
60ad7ce60aSkettenis #define TIPMIC_BATTEMP_LO		0x59
61ad7ce60aSkettenis #define TIPMIC_SYSTEMP_HI		0x5a
62ad7ce60aSkettenis #define TIPMIC_SYSTEMP_LO		0x5b
63ad7ce60aSkettenis 
64ad7ce60aSkettenis #define TIPMIC_REGIONSPACE_THERMAL	0x8c
65237e378aSkettenis #define TIPMIC_REGIONSPACE_POWER	0x8d
66ad7ce60aSkettenis 
67ad7ce60aSkettenis struct acpi_lpat {
68ad7ce60aSkettenis 	int32_t temp;
69ad7ce60aSkettenis 	int32_t raw;
70ad7ce60aSkettenis };
71ad7ce60aSkettenis 
72ad7ce60aSkettenis struct tipmic_softc {
73ad7ce60aSkettenis 	struct device	sc_dev;
74ad7ce60aSkettenis 	struct acpi_softc *sc_acpi;
75ad7ce60aSkettenis 	struct aml_node *sc_node;
76ad7ce60aSkettenis 	i2c_tag_t	sc_tag;
77ad7ce60aSkettenis 	i2c_addr_t	sc_addr;
78ad7ce60aSkettenis 
79ad7ce60aSkettenis 	void		*sc_ih;
80ad7ce60aSkettenis 	volatile int	sc_stat_adc;
81ad7ce60aSkettenis 
82ad7ce60aSkettenis 	struct acpi_lpat *sc_lpat;
83ad7ce60aSkettenis 	size_t		sc_lpat_len;
84ad7ce60aSkettenis 
85ad7ce60aSkettenis 	struct acpi_gpio sc_gpio;
86ad7ce60aSkettenis };
87ad7ce60aSkettenis 
88ad7ce60aSkettenis int	tipmic_match(struct device *, void *, void *);
89ad7ce60aSkettenis void	tipmic_attach(struct device *, struct device *, void *);
90ad7ce60aSkettenis 
91471aeecfSnaddy const struct cfattach tipmic_ca = {
92ad7ce60aSkettenis 	sizeof(struct tipmic_softc), tipmic_match, tipmic_attach
93ad7ce60aSkettenis };
94ad7ce60aSkettenis 
95ad7ce60aSkettenis struct cfdriver tipmic_cd = {
96ad7ce60aSkettenis 	NULL, "tipmic", DV_DULL
97ad7ce60aSkettenis };
98ad7ce60aSkettenis 
99ad7ce60aSkettenis uint8_t	tipmic_read_1(struct tipmic_softc *, uint8_t, int);
100ad7ce60aSkettenis void	tipmic_write_1(struct tipmic_softc *, uint8_t, uint8_t, int);
101ad7ce60aSkettenis int	tipmic_intr(void *);
102ad7ce60aSkettenis void	tipmic_get_lpat(struct tipmic_softc *);
103ad7ce60aSkettenis int32_t	tipmic_raw_to_temp(struct tipmic_softc *, int32_t);
104ad7ce60aSkettenis int	tipmic_thermal_opreg_handler(void *, int, uint64_t, int, uint64_t *);
105237e378aSkettenis int	tipmic_power_opreg_handler(void *, int, uint64_t, int, uint64_t *);
106ad7ce60aSkettenis int	tipmic_read_pin(void *, int);
107ad7ce60aSkettenis void	tipmic_write_pin(void *, int, int);
108ad7ce60aSkettenis 
109ad7ce60aSkettenis int
tipmic_match(struct device * parent,void * match,void * aux)110ad7ce60aSkettenis tipmic_match(struct device *parent, void *match, void *aux)
111ad7ce60aSkettenis {
112ad7ce60aSkettenis 	struct i2c_attach_args *ia = aux;
113ad7ce60aSkettenis 
114ad7ce60aSkettenis 	return (strcmp(ia->ia_name, "INT33F5") == 0);
115ad7ce60aSkettenis }
116ad7ce60aSkettenis 
117ad7ce60aSkettenis void
tipmic_attach(struct device * parent,struct device * self,void * aux)118ad7ce60aSkettenis tipmic_attach(struct device *parent, struct device *self, void *aux)
119ad7ce60aSkettenis {
120ad7ce60aSkettenis 	struct tipmic_softc *sc = (struct tipmic_softc *)self;
121ad7ce60aSkettenis 	struct i2c_attach_args *ia = aux;
122ad7ce60aSkettenis 
123ad7ce60aSkettenis 	sc->sc_tag = ia->ia_tag;
124ad7ce60aSkettenis 	sc->sc_addr = ia->ia_addr;
125ad7ce60aSkettenis 	sc->sc_acpi = acpi_softc;
126ad7ce60aSkettenis 	sc->sc_node = ia->ia_cookie;
127ad7ce60aSkettenis 
128ad7ce60aSkettenis 	if (ia->ia_intr == NULL) {
129ad7ce60aSkettenis 		printf(": no interrupt\n");
130ad7ce60aSkettenis 		return;
131ad7ce60aSkettenis 	}
132ad7ce60aSkettenis 
133ad7ce60aSkettenis 	/* Mask all interrupts before we install our interrupt handler. */
134ad7ce60aSkettenis 	tipmic_write_1(sc, TIPMIC_INTR_MASK, TIPMIC_INTR_MASK_ALL, I2C_F_POLL);
135ad7ce60aSkettenis 
136ad7ce60aSkettenis 	printf(" %s", iic_intr_string(sc->sc_tag, ia->ia_intr));
137ad7ce60aSkettenis 	sc->sc_ih = iic_intr_establish(sc->sc_tag, ia->ia_intr,
138ad7ce60aSkettenis 	    IPL_BIO, tipmic_intr, sc, sc->sc_dev.dv_xname);
139ad7ce60aSkettenis 	if (sc->sc_ih == NULL) {
140ad7ce60aSkettenis 		printf(": can't establish interrupt\n");
141ad7ce60aSkettenis 		return;
142ad7ce60aSkettenis 	}
143ad7ce60aSkettenis 
144ad7ce60aSkettenis 	printf("\n");
145ad7ce60aSkettenis 
146ad7ce60aSkettenis 	tipmic_get_lpat(sc);
147ad7ce60aSkettenis 	if (sc->sc_lpat == NULL)
148ad7ce60aSkettenis 		return;
149ad7ce60aSkettenis 
150ad7ce60aSkettenis 	sc->sc_gpio.cookie = sc;
151ad7ce60aSkettenis 	sc->sc_gpio.read_pin = tipmic_read_pin;
152ad7ce60aSkettenis 	sc->sc_gpio.write_pin = tipmic_write_pin;
153ad7ce60aSkettenis 	sc->sc_node->gpio = &sc->sc_gpio;
154ad7ce60aSkettenis 	acpi_register_gpio(sc->sc_acpi, sc->sc_node);
155ad7ce60aSkettenis 
156ad7ce60aSkettenis 	/* Register OEM defined address space. */
157ad7ce60aSkettenis 	aml_register_regionspace(sc->sc_node, TIPMIC_REGIONSPACE_THERMAL,
158ad7ce60aSkettenis 	    sc, tipmic_thermal_opreg_handler);
159237e378aSkettenis 	aml_register_regionspace(sc->sc_node, TIPMIC_REGIONSPACE_POWER,
160237e378aSkettenis 	    sc, tipmic_power_opreg_handler);
161ad7ce60aSkettenis }
162ad7ce60aSkettenis 
163ad7ce60aSkettenis uint8_t
tipmic_read_1(struct tipmic_softc * sc,uint8_t reg,int flags)164ad7ce60aSkettenis tipmic_read_1(struct tipmic_softc *sc, uint8_t reg, int flags)
165ad7ce60aSkettenis {
166ad7ce60aSkettenis 	uint8_t val;
167ad7ce60aSkettenis 	int error;
168ad7ce60aSkettenis 
169ad7ce60aSkettenis 	iic_acquire_bus(sc->sc_tag, flags);
170ad7ce60aSkettenis 	error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
171ad7ce60aSkettenis 	    &reg, sizeof(reg), &val, sizeof(val), flags);
172ad7ce60aSkettenis 	iic_release_bus(sc->sc_tag, flags);
173ad7ce60aSkettenis 
174ad7ce60aSkettenis 	if (error) {
175ad7ce60aSkettenis 		printf("%s: can't read register 0x%02x\n",
176ad7ce60aSkettenis 		    sc->sc_dev.dv_xname, reg);
177ad7ce60aSkettenis 		val = 0xff;
178ad7ce60aSkettenis 	}
179ad7ce60aSkettenis 
180ad7ce60aSkettenis 	return val;
181ad7ce60aSkettenis }
182ad7ce60aSkettenis 
183ad7ce60aSkettenis void
tipmic_write_1(struct tipmic_softc * sc,uint8_t reg,uint8_t val,int flags)184ad7ce60aSkettenis tipmic_write_1(struct tipmic_softc *sc, uint8_t reg, uint8_t val, int flags)
185ad7ce60aSkettenis {
186ad7ce60aSkettenis 	int error;
187ad7ce60aSkettenis 
188ad7ce60aSkettenis 	iic_acquire_bus(sc->sc_tag, flags);
189ad7ce60aSkettenis 	error = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
190ad7ce60aSkettenis 	    &reg, sizeof(reg), &val, sizeof(val), flags);
191ad7ce60aSkettenis 	iic_release_bus(sc->sc_tag, flags);
192ad7ce60aSkettenis 
193ad7ce60aSkettenis 	if (error) {
194ad7ce60aSkettenis 		printf("%s: can't write register 0x%02x\n",
195ad7ce60aSkettenis 		    sc->sc_dev.dv_xname, reg);
196ad7ce60aSkettenis 	}
197ad7ce60aSkettenis }
198ad7ce60aSkettenis 
199ad7ce60aSkettenis int
tipmic_intr(void * arg)200ad7ce60aSkettenis tipmic_intr(void *arg)
201ad7ce60aSkettenis {
202ad7ce60aSkettenis 	struct tipmic_softc *sc = arg;
203ad7ce60aSkettenis 	int handled = 0;
204ad7ce60aSkettenis 	uint8_t stat;
205ad7ce60aSkettenis 
206ad7ce60aSkettenis 	stat = tipmic_read_1(sc, TIPMIC_INTR_STAT, I2C_F_POLL);
207ad7ce60aSkettenis 	tipmic_write_1(sc, TIPMIC_INTR_STAT, stat, I2C_F_POLL);
208ad7ce60aSkettenis 	if (stat & TIPMIC_INTR_STAT_ADC) {
209ad7ce60aSkettenis 		sc->sc_stat_adc = 1;
210ad7ce60aSkettenis 		wakeup(&sc->sc_stat_adc);
211ad7ce60aSkettenis 		handled = 1;
212ad7ce60aSkettenis 	}
213ad7ce60aSkettenis 
214ad7ce60aSkettenis 	return handled;
215ad7ce60aSkettenis }
216ad7ce60aSkettenis 
217ad7ce60aSkettenis void
tipmic_get_lpat(struct tipmic_softc * sc)218ad7ce60aSkettenis tipmic_get_lpat(struct tipmic_softc *sc)
219ad7ce60aSkettenis {
220ad7ce60aSkettenis 	struct aml_value res;
221ad7ce60aSkettenis 	int i;
222ad7ce60aSkettenis 
223ad7ce60aSkettenis 	if (aml_evalname(sc->sc_acpi, sc->sc_node, "LPAT", 0, NULL, &res))
224ad7ce60aSkettenis 		return;
225ad7ce60aSkettenis 	if (res.type != AML_OBJTYPE_PACKAGE)
226ad7ce60aSkettenis 		goto out;
227ad7ce60aSkettenis 	if (res.length < 4 || (res.length % 2) != 0)
228ad7ce60aSkettenis 		goto out;
229ad7ce60aSkettenis 
230ad7ce60aSkettenis 	sc->sc_lpat_len = res.length / 2;
231ad7ce60aSkettenis 	sc->sc_lpat = mallocarray(sc->sc_lpat_len, sizeof(struct acpi_lpat),
232ad7ce60aSkettenis 	    M_DEVBUF, M_WAITOK);
233ad7ce60aSkettenis 
234ad7ce60aSkettenis 	for (i = 0; i < sc->sc_lpat_len; i++) {
235ad7ce60aSkettenis 		sc->sc_lpat[i].temp = aml_val2int(res.v_package[2 * i]);
236ad7ce60aSkettenis 		sc->sc_lpat[i].raw = aml_val2int(res.v_package[2 * i + 1]);
237ad7ce60aSkettenis 	}
238ad7ce60aSkettenis 
239ad7ce60aSkettenis out:
240ad7ce60aSkettenis 	aml_freevalue(&res);
241ad7ce60aSkettenis }
242ad7ce60aSkettenis 
243ad7ce60aSkettenis int32_t
tipmic_raw_to_temp(struct tipmic_softc * sc,int32_t raw)244ad7ce60aSkettenis tipmic_raw_to_temp(struct tipmic_softc *sc, int32_t raw)
245ad7ce60aSkettenis {
246ad7ce60aSkettenis 	struct acpi_lpat *lpat = sc->sc_lpat;
247ad7ce60aSkettenis 	int32_t raw0, delta_raw;
248ad7ce60aSkettenis 	int32_t temp0, delta_temp;
249ad7ce60aSkettenis 	int i;
250ad7ce60aSkettenis 
251ad7ce60aSkettenis 	for (i = 1; i < sc->sc_lpat_len; i++) {
252ad7ce60aSkettenis 		/* Coefficient can be positive or negative. */
253ad7ce60aSkettenis 		if (raw >= lpat[i - 1].raw && raw <= lpat[i].raw)
254ad7ce60aSkettenis 			break;
255ad7ce60aSkettenis 		if (raw <= lpat[i - 1].raw && raw >= lpat[i].raw)
256ad7ce60aSkettenis 			break;
257ad7ce60aSkettenis 	}
258ad7ce60aSkettenis 	if (i == sc->sc_lpat_len)
259ad7ce60aSkettenis 		return -1;
260ad7ce60aSkettenis 
261ad7ce60aSkettenis 	raw0 = lpat[i - 1].raw;
262ad7ce60aSkettenis 	temp0 = lpat[i - 1].temp;
263ad7ce60aSkettenis 	delta_raw = lpat[i].raw - raw0;
264ad7ce60aSkettenis 	delta_temp = lpat[i].temp - temp0;
265ad7ce60aSkettenis 
266ad7ce60aSkettenis 	return temp0 + (raw - raw0) * delta_temp / delta_raw;
267ad7ce60aSkettenis }
268ad7ce60aSkettenis 
269ad7ce60aSkettenis struct tipmic_regmap {
270ad7ce60aSkettenis 	uint8_t address;
271ad7ce60aSkettenis 	uint8_t hi, lo;
272ad7ce60aSkettenis };
273ad7ce60aSkettenis 
274ad7ce60aSkettenis struct tipmic_regmap tipmic_thermal_regmap[] = {
275386da3b3Skettenis 	{ 0x00, TIPMIC_SYSTEMP_HI, TIPMIC_SYSTEMP_LO },
276ad7ce60aSkettenis 	{ 0x18, TIPMIC_SYSTEMP_HI, TIPMIC_SYSTEMP_LO }
277ad7ce60aSkettenis };
278ad7ce60aSkettenis 
279*c6789160Sdlg static int
tipmic_wait_adc(struct tipmic_softc * sc)280*c6789160Sdlg tipmic_wait_adc(struct tipmic_softc *sc)
281*c6789160Sdlg {
282*c6789160Sdlg 	int i;
283*c6789160Sdlg 
284*c6789160Sdlg 	if (!cold) {
285*c6789160Sdlg 		return (tsleep_nsec(&sc->sc_stat_adc, PRIBIO, "tipmic",
286*c6789160Sdlg 		    SEC_TO_NSEC(1)));
287*c6789160Sdlg 	}
288*c6789160Sdlg 
289*c6789160Sdlg 	for (i = 0; i < 1000; i++) {
290*c6789160Sdlg 		delay(1000);
291*c6789160Sdlg 		if (tipmic_intr(sc) == 1)
292*c6789160Sdlg 			return (0);
293*c6789160Sdlg 	}
294*c6789160Sdlg 
295*c6789160Sdlg 	return (EWOULDBLOCK);
296*c6789160Sdlg }
297*c6789160Sdlg 
298ad7ce60aSkettenis int
tipmic_thermal_opreg_handler(void * cookie,int iodir,uint64_t address,int size,uint64_t * value)299ad7ce60aSkettenis tipmic_thermal_opreg_handler(void *cookie, int iodir, uint64_t address,
300ad7ce60aSkettenis     int size, uint64_t *value)
301ad7ce60aSkettenis {
302ad7ce60aSkettenis 	struct tipmic_softc *sc = cookie;
303ad7ce60aSkettenis 	int32_t temp;
304ad7ce60aSkettenis 	uint16_t raw;
305ad7ce60aSkettenis 	uint8_t hi, lo;
306ad7ce60aSkettenis 	uint8_t reg;
307ad7ce60aSkettenis 	int i, s;
308ad7ce60aSkettenis 
309ad7ce60aSkettenis 	/* Only allow 32-bit read access. */
310ad7ce60aSkettenis 	if (size != 4 || iodir != ACPI_IOREAD)
311ad7ce60aSkettenis 		return -1;
312ad7ce60aSkettenis 
313ad7ce60aSkettenis 	for (i = 0; i < nitems(tipmic_thermal_regmap); i++) {
314ad7ce60aSkettenis 		if (address == tipmic_thermal_regmap[i].address)
315ad7ce60aSkettenis 			break;
316ad7ce60aSkettenis 	}
31707275e03Skettenis 	if (i == nitems(tipmic_thermal_regmap)) {
31807275e03Skettenis 		printf("%s: addr 0x%02llx\n", __func__, address);
319ad7ce60aSkettenis 		return -1;
32007275e03Skettenis 	}
321ad7ce60aSkettenis 
322ad7ce60aSkettenis 	/* Turn ADC on and select the appropriate channel. */
323ad7ce60aSkettenis 	reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0);
324ad7ce60aSkettenis 	reg |= TIPMIC_ADC_CTRL_EN;
325ad7ce60aSkettenis 	tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0);
326ad7ce60aSkettenis 	switch (tipmic_thermal_regmap[i].hi) {
327ad7ce60aSkettenis 	case TIPMIC_SYSTEMP_HI:
328ad7ce60aSkettenis 		reg |= TIPMIC_ADC_CTRL_CH_SYSTEMP;
329ad7ce60aSkettenis 		break;
330ad7ce60aSkettenis 	default:
331ad7ce60aSkettenis 		panic("%s: unsupported channel", sc->sc_dev.dv_xname);
332ad7ce60aSkettenis 	}
333ad7ce60aSkettenis 	tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0);
334ad7ce60aSkettenis 
335ad7ce60aSkettenis 	/* Need to wait 50us before starting the conversion. */
336ad7ce60aSkettenis 	delay(50);
337ad7ce60aSkettenis 
338ad7ce60aSkettenis 	/* Start conversion. */
339ad7ce60aSkettenis 	sc->sc_stat_adc = 0;
340ad7ce60aSkettenis 	reg |= TIPMIC_ADC_CTRL_START;
341ad7ce60aSkettenis 	tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0);
342ad7ce60aSkettenis 
343ad7ce60aSkettenis 	/*
344ad7ce60aSkettenis 	 * Block interrupts to prevent I2C access from the interrupt
345ad7ce60aSkettenis 	 * handler during the completion of the write that unmasks the
346ad7ce60aSkettenis 	 * ADC interrupt.
347ad7ce60aSkettenis 	 */
348ad7ce60aSkettenis 	s = splbio();
349ad7ce60aSkettenis 	reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL);
350ad7ce60aSkettenis 	reg &= ~TIPMIC_INTR_MASK_ADC;
351ad7ce60aSkettenis 	tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL);
352ad7ce60aSkettenis 	splx(s);
353ad7ce60aSkettenis 
354ad7ce60aSkettenis 	while (sc->sc_stat_adc == 0) {
355*c6789160Sdlg 		if (tipmic_wait_adc(sc)) {
356ad7ce60aSkettenis 			printf("%s: ADC timeout\n", sc->sc_dev.dv_xname);
357ad7ce60aSkettenis 			break;
358ad7ce60aSkettenis 		}
359ad7ce60aSkettenis 	}
360ad7ce60aSkettenis 
361ad7ce60aSkettenis 	/* Mask ADC interrupt again. */
362ad7ce60aSkettenis 	s = splbio();
363ad7ce60aSkettenis 	reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL);
364ad7ce60aSkettenis 	reg |= TIPMIC_INTR_MASK_ADC;
365ad7ce60aSkettenis 	tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL);
366ad7ce60aSkettenis 	splx(s);
367ad7ce60aSkettenis 
368ad7ce60aSkettenis 	hi = tipmic_thermal_regmap[i].hi;
369ad7ce60aSkettenis 	lo = tipmic_thermal_regmap[i].lo;
370ad7ce60aSkettenis 	raw = (tipmic_read_1(sc, hi, 0) & 0x03) << 8;
371ad7ce60aSkettenis 	raw |= tipmic_read_1(sc, lo, 0);
372ad7ce60aSkettenis 
373ad7ce60aSkettenis 	/* Turn ADC off. */
374ad7ce60aSkettenis 	reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0);
375ad7ce60aSkettenis 	reg &= ~(TIPMIC_ADC_CTRL_EN | TIPMIC_ADC_CTRL_CH_MASK);
376ad7ce60aSkettenis 	tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0);
377ad7ce60aSkettenis 
378ad7ce60aSkettenis 	temp = tipmic_raw_to_temp(sc, raw);
379ad7ce60aSkettenis 	if (temp < 0)
380ad7ce60aSkettenis 		return -1;
381ad7ce60aSkettenis 
382ad7ce60aSkettenis 	*value = temp;
383ad7ce60aSkettenis 	return 0;
384ad7ce60aSkettenis }
385ad7ce60aSkettenis 
386237e378aSkettenis struct tipmic_regmap tipmic_power_regmap[] = {
387237e378aSkettenis 	{ 0x00, TIPMIC_LDO1_CTRL },
388237e378aSkettenis 	{ 0x04, TIPMIC_LDO2_CTRL },
389237e378aSkettenis 	{ 0x08, TIPMIC_LDO3_CTRL },
390237e378aSkettenis 	{ 0x0c, TIPMIC_LDO5_CTRL },
391237e378aSkettenis 	{ 0x10, TIPMIC_LDO6_CTRL },
392237e378aSkettenis 	{ 0x14, TIPMIC_LDO7_CTRL },
393237e378aSkettenis 	{ 0x18, TIPMIC_LDO8_CTRL },
394237e378aSkettenis 	{ 0x1c, TIPMIC_LDO9_CTRL },
395237e378aSkettenis 	{ 0x20, TIPMIC_LDO10_CTRL },
396237e378aSkettenis 	{ 0x24, TIPMIC_LDO11_CTRL },
397237e378aSkettenis 	{ 0x28, TIPMIC_LDO12_CTRL },
398237e378aSkettenis 	{ 0x2c, TIPMIC_LDO13_CTRL },
399237e378aSkettenis 	{ 0x30, TIPMIC_LDO14_CTRL }
400237e378aSkettenis };
401237e378aSkettenis 
402237e378aSkettenis int
tipmic_power_opreg_handler(void * cookie,int iodir,uint64_t address,int size,uint64_t * value)403237e378aSkettenis tipmic_power_opreg_handler(void *cookie, int iodir, uint64_t address,
404237e378aSkettenis     int size, uint64_t *value)
405237e378aSkettenis {
406237e378aSkettenis 	struct tipmic_softc *sc = cookie;
407237e378aSkettenis 	uint8_t reg, val;
408237e378aSkettenis 	int i;
409237e378aSkettenis 
410237e378aSkettenis 	/* Only allow 32-bit access. */
411237e378aSkettenis 	if (size != 4)
412237e378aSkettenis 		return -1;
413237e378aSkettenis 
414237e378aSkettenis 	for (i = 0; i < nitems(tipmic_power_regmap); i++) {
415237e378aSkettenis 		if (address == tipmic_power_regmap[i].address)
416237e378aSkettenis 			break;
417237e378aSkettenis 	}
41807275e03Skettenis 	if (i == nitems(tipmic_power_regmap)) {
41907275e03Skettenis 		printf("%s: addr 0x%02llx\n", __func__, address);
420237e378aSkettenis 		return -1;
42107275e03Skettenis 	}
422237e378aSkettenis 
423237e378aSkettenis 	reg = tipmic_power_regmap[i].hi;
424237e378aSkettenis 	val = tipmic_read_1(sc, reg, 0);
425237e378aSkettenis 	if (iodir == ACPI_IOREAD) {
426237e378aSkettenis 		*value = val & 0x1;
427237e378aSkettenis 	} else {
428237e378aSkettenis 		if (*value)
429237e378aSkettenis 			val |= 0x1;
430237e378aSkettenis 		else
431237e378aSkettenis 			val &= ~0x1;
432237e378aSkettenis 		tipmic_write_1(sc, reg, val, 0);
433237e378aSkettenis 	}
434237e378aSkettenis 
435237e378aSkettenis 	return 0;
436237e378aSkettenis }
437237e378aSkettenis 
438ad7ce60aSkettenis /*
4394b1a56afSjsg  * Allegedly the GPIOs are virtual and only there to deal with a
440ad7ce60aSkettenis  * limitation of Microsoft Windows.
441ad7ce60aSkettenis  */
442ad7ce60aSkettenis 
443ad7ce60aSkettenis int
tipmic_read_pin(void * cookie,int pin)444ad7ce60aSkettenis tipmic_read_pin(void *cookie, int pin)
445ad7ce60aSkettenis {
446ad7ce60aSkettenis 	return 0;
447ad7ce60aSkettenis }
448ad7ce60aSkettenis 
449ad7ce60aSkettenis void
tipmic_write_pin(void * cookie,int pin,int value)450ad7ce60aSkettenis tipmic_write_pin(void *cookie, int pin, int value)
451ad7ce60aSkettenis {
452ad7ce60aSkettenis }
453