xref: /openbsd/sys/dev/acpi/tipmic.c (revision e5dd7070)
1 /*	$OpenBSD: tipmic.c,v 1.5 2020/01/09 14:35:19 mpi 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 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
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
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
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
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
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
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
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 int
280 tipmic_thermal_opreg_handler(void *cookie, int iodir, uint64_t address,
281     int size, uint64_t *value)
282 {
283 	struct tipmic_softc *sc = cookie;
284 	int32_t temp;
285 	uint16_t raw;
286 	uint8_t hi, lo;
287 	uint8_t reg;
288 	int i, s;
289 
290 	/* Only allow 32-bit read access. */
291 	if (size != 4 || iodir != ACPI_IOREAD)
292 		return -1;
293 
294 	for (i = 0; i < nitems(tipmic_thermal_regmap); i++) {
295 		if (address == tipmic_thermal_regmap[i].address)
296 			break;
297 	}
298 	if (i == nitems(tipmic_thermal_regmap)) {
299 		printf("%s: addr 0x%02llx\n", __func__, address);
300 		return -1;
301 	}
302 
303 	/* Turn ADC on and select the appropriate channel. */
304 	reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0);
305 	reg |= TIPMIC_ADC_CTRL_EN;
306 	tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0);
307 	switch (tipmic_thermal_regmap[i].hi) {
308 	case TIPMIC_SYSTEMP_HI:
309 		reg |= TIPMIC_ADC_CTRL_CH_SYSTEMP;
310 		break;
311 	default:
312 		panic("%s: unsupported channel", sc->sc_dev.dv_xname);
313 	}
314 	tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0);
315 
316 	/* Need to wait 50us before starting the conversion. */
317 	delay(50);
318 
319 	/* Start conversion. */
320 	sc->sc_stat_adc = 0;
321 	reg |= TIPMIC_ADC_CTRL_START;
322 	tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0);
323 
324 	/*
325 	 * Block interrupts to prevent I2C access from the interrupt
326 	 * handler during the completion of the write that unmasks the
327 	 * ADC interrupt.
328 	 */
329 	s = splbio();
330 	reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL);
331 	reg &= ~TIPMIC_INTR_MASK_ADC;
332 	tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL);
333 	splx(s);
334 
335 	while (sc->sc_stat_adc == 0) {
336 		if (tsleep_nsec(&sc->sc_stat_adc, PRIBIO, "tipmic",
337 		    SEC_TO_NSEC(1))) {
338 			printf("%s: ADC timeout\n", sc->sc_dev.dv_xname);
339 			break;
340 		}
341 	}
342 
343 	/* Mask ADC interrupt again. */
344 	s = splbio();
345 	reg = tipmic_read_1(sc, TIPMIC_INTR_MASK, I2C_F_POLL);
346 	reg |= TIPMIC_INTR_MASK_ADC;
347 	tipmic_write_1(sc, TIPMIC_INTR_MASK, reg, I2C_F_POLL);
348 	splx(s);
349 
350 	hi = tipmic_thermal_regmap[i].hi;
351 	lo = tipmic_thermal_regmap[i].lo;
352 	raw = (tipmic_read_1(sc, hi, 0) & 0x03) << 8;
353 	raw |= tipmic_read_1(sc, lo, 0);
354 
355 	/* Turn ADC off. */
356 	reg = tipmic_read_1(sc, TIPMIC_ADC_CTRL, 0);
357 	reg &= ~(TIPMIC_ADC_CTRL_EN | TIPMIC_ADC_CTRL_CH_MASK);
358 	tipmic_write_1(sc, TIPMIC_ADC_CTRL, reg, 0);
359 
360 	temp = tipmic_raw_to_temp(sc, raw);
361 	if (temp < 0)
362 		return -1;
363 
364 	*value = temp;
365 	return 0;
366 }
367 
368 struct tipmic_regmap tipmic_power_regmap[] = {
369 	{ 0x00, TIPMIC_LDO1_CTRL },
370 	{ 0x04, TIPMIC_LDO2_CTRL },
371 	{ 0x08, TIPMIC_LDO3_CTRL },
372 	{ 0x0c, TIPMIC_LDO5_CTRL },
373 	{ 0x10, TIPMIC_LDO6_CTRL },
374 	{ 0x14, TIPMIC_LDO7_CTRL },
375 	{ 0x18, TIPMIC_LDO8_CTRL },
376 	{ 0x1c, TIPMIC_LDO9_CTRL },
377 	{ 0x20, TIPMIC_LDO10_CTRL },
378 	{ 0x24, TIPMIC_LDO11_CTRL },
379 	{ 0x28, TIPMIC_LDO12_CTRL },
380 	{ 0x2c, TIPMIC_LDO13_CTRL },
381 	{ 0x30, TIPMIC_LDO14_CTRL }
382 };
383 
384 int
385 tipmic_power_opreg_handler(void *cookie, int iodir, uint64_t address,
386     int size, uint64_t *value)
387 {
388 	struct tipmic_softc *sc = cookie;
389 	uint8_t reg, val;
390 	int i;
391 
392 	/* Only allow 32-bit access. */
393 	if (size != 4)
394 		return -1;
395 
396 	for (i = 0; i < nitems(tipmic_power_regmap); i++) {
397 		if (address == tipmic_power_regmap[i].address)
398 			break;
399 	}
400 	if (i == nitems(tipmic_power_regmap)) {
401 		printf("%s: addr 0x%02llx\n", __func__, address);
402 		return -1;
403 	}
404 
405 	reg = tipmic_power_regmap[i].hi;
406 	val = tipmic_read_1(sc, reg, 0);
407 	if (iodir == ACPI_IOREAD) {
408 		*value = val & 0x1;
409 	} else {
410 		if (*value)
411 			val |= 0x1;
412 		else
413 			val &= ~0x1;
414 		tipmic_write_1(sc, reg, val, 0);
415 	}
416 
417 	return 0;
418 }
419 
420 /*
421  * Allegdly the GPIOs are virtual and only there to deal with a
422  * limitation of Microsoft Windows.
423  */
424 
425 int
426 tipmic_read_pin(void *cookie, int pin)
427 {
428 	return 0;
429 }
430 
431 void
432 tipmic_write_pin(void *cookie, int pin, int value)
433 {
434 }
435