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 ®, 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 ®, 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