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