xref: /openbsd-src/sys/dev/fdt/rktemp.c (revision 1ad61ae0a79a724d2d3ec69e69c8e1d1ff6b53a0)
1 /*	$OpenBSD: rktemp.c,v 1.12 2023/03/05 09:57:32 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2017 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/sensors.h>
22 
23 #include <machine/intr.h>
24 #include <machine/bus.h>
25 #include <machine/fdt.h>
26 
27 #include <dev/ofw/openfirm.h>
28 #include <dev/ofw/ofw_clock.h>
29 #include <dev/ofw/ofw_misc.h>
30 #include <dev/ofw/ofw_pinctrl.h>
31 #include <dev/ofw/ofw_thermal.h>
32 #include <dev/ofw/fdt.h>
33 
34 /* Registers */
35 #define TSADC_USER_CON			0x0000
36 #define  TSADC_USER_CON_INTER_PD_SOC_SHIFT	6
37 #define TSADC_AUTO_CON			0x0004
38 #define  TSADC_AUTO_CON_TSHUT_POLARITY	(1 << 8)
39 #define  TSADC_AUTO_CON_SRC3_EN		(1 << 7)
40 #define  TSADC_AUTO_CON_SRC2_EN		(1 << 6)
41 #define  TSADC_AUTO_CON_SRC1_EN		(1 << 5)
42 #define  TSADC_AUTO_CON_SRC0_EN		(1 << 4)
43 #define  TSADC_AUTO_CON_TSADC_Q_SEL	(1 << 1)
44 #define  TSADC_AUTO_CON_AUTO_EN		(1 << 0)
45 #define TSADC_INT_EN			0x0008
46 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC3	(1 << 11)
47 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC2	(1 << 10)
48 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC1	(1 << 9)
49 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC0	(1 << 8)
50 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC3	(1 << 7)
51 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC2	(1 << 6)
52 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1	(1 << 5)
53 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0	(1 << 4)
54 #define TSADC_INT_PD			0x000c
55 #define  TSADC_INT_PD_TSHUT_O_SRC0		(1 << 4)
56 #define  TSADC_INT_PD_TSHUT_O_SRC1		(1 << 5)
57 #define  TSADC_INT_PD_TSHUT_O_SRC2		(1 << 6)
58 #define  TSADC_INT_PD_TSHUT_O_SRC3		(1 << 7)
59 #define TSADC_DATA0			0x0020
60 #define TSADC_DATA1			0x0024
61 #define TSADC_DATA2			0x0028
62 #define TSADC_DATA3			0x002c
63 #define TSADC_COMP0_INT			0x0030
64 #define TSADC_COMP1_INT			0x0034
65 #define TSADC_COMP2_INT			0x0038
66 #define TSADC_COMP3_INT			0x003c
67 #define TSADC_COMP0_SHUT		0x0040
68 #define TSADC_COMP1_SHUT		0x0044
69 #define TSADC_COMP2_SHUT		0x0048
70 #define TSADC_COMP3_SHUT		0x004c
71 #define TSADC_HIGHT_INT_DEBOUNCE	0x0060
72 #define TSADC_HIGHT_TSHUT_DEBOUNCE	0x0064
73 #define TSADC_AUTO_PERIOD		0x0068
74 #define TSADC_AUTO_PERIOD_HT		0x006c
75 
76 /* RK3568 */
77 #define RK3568_GRF_TSADC_CON		0x0600
78 #define  RK3568_GRF_TSADC_EN		(1 << 8)
79 #define  RK3568_GRF_TSADC_ANA_REG(idx)	(1 << (idx))
80 
81 #define HREAD4(sc, reg)							\
82 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
83 #define HWRITE4(sc, reg, val)						\
84 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
85 
86 struct rktemp_entry {
87 	int32_t temp;
88 	int32_t code;
89 };
90 
91 /* RK3288 conversion table. */
92 const struct rktemp_entry rk3288_temps[] = {
93 	{ -40000, 3800 },
94 	{ -35000, 3792 },
95 	{ -30000, 3783 },
96 	{ -25000, 3774 },
97 	{ -20000, 3765 },
98 	{ -15000, 3756 },
99 	{ -10000, 3747 },
100 	{  -5000, 3737 },
101 	{      0, 3728 },
102 	{   5000, 3718 },
103 	{  10000, 3708 },
104 	{  15000, 3698 },
105 	{  20000, 3688 },
106 	{  25000, 3678 },
107 	{  30000, 3667 },
108 	{  35000, 3656 },
109 	{  40000, 3645 },
110 	{  45000, 3634 },
111 	{  50000, 3623 },
112 	{  55000, 3611 },
113 	{  60000, 3600 },
114 	{  65000, 3588 },
115 	{  70000, 3575 },
116 	{  75000, 3563 },
117 	{  80000, 3550 },
118 	{  85000, 3537 },
119 	{  90000, 3524 },
120 	{  95000, 3510 },
121 	{ 100000, 3496 },
122 	{ 105000, 3482 },
123 	{ 110000, 3467 },
124 	{ 115000, 3452 },
125 	{ 120000, 3437 },
126 	{ 125000, 3421 },
127 };
128 
129 const char *const rk3288_names[] = { "", "CPU", "GPU" };
130 
131 /* RK3328 conversion table. */
132 const struct rktemp_entry rk3328_temps[] = {
133 	{ -40000, 296 },
134 	{ -35000, 304 },
135 	{ -30000, 313 },
136 	{ -20000, 331 },
137 	{ -15000, 340 },
138 	{ -10000, 349 },
139 	{  -5000, 359 },
140 	{      0, 368 },
141 	{   5000, 378 },
142 	{  10000, 388 },
143 	{  15000, 398 },
144 	{  20000, 408 },
145 	{  25000, 418 },
146 	{  30000, 429 },
147 	{  35000, 440 },
148 	{  40000, 451 },
149 	{  45000, 462 },
150 	{  50000, 473 },
151 	{  55000, 485 },
152 	{  60000, 496 },
153 	{  65000, 508 },
154 	{  70000, 521 },
155 	{  75000, 533 },
156 	{  80000, 546 },
157 	{  85000, 559 },
158 	{  90000, 572 },
159 	{  95000, 586 },
160 	{ 100000, 600 },
161 	{ 105000, 614 },
162 	{ 110000, 629 },
163 	{ 115000, 644 },
164 	{ 120000, 659 },
165 	{ 125000, 675 },
166 };
167 
168 const char *const rk3308_names[] = { "CPU", "GPU" };
169 const char *const rk3328_names[] = { "CPU" };
170 
171 /* RK3399 conversion table. */
172 const struct rktemp_entry rk3399_temps[] = {
173 	{ -40000, 402 },
174 	{ -35000, 410 },
175 	{ -30000, 419 },
176 	{ -25000, 427 },
177 	{ -20000, 436 },
178 	{ -15000, 444 },
179 	{ -10000, 453 },
180 	{  -5000, 461 },
181 	{      0, 470 },
182 	{   5000, 478 },
183 	{  10000, 487 },
184 	{  15000, 496 },
185 	{  20000, 504 },
186 	{  25000, 513 },
187 	{  30000, 521 },
188 	{  35000, 530 },
189 	{  40000, 538 },
190 	{  45000, 547 },
191 	{  50000, 555 },
192 	{  55000, 564 },
193 	{  60000, 573 },
194 	{  65000, 581 },
195 	{  70000, 590 },
196 	{  75000, 599 },
197 	{  80000, 607 },
198 	{  85000, 616 },
199 	{  90000, 624 },
200 	{  95000, 633 },
201 	{ 100000, 642 },
202 	{ 105000, 650 },
203 	{ 110000, 659 },
204 	{ 115000, 668 },
205 	{ 120000, 677 },
206 	{ 125000, 685 },
207 };
208 
209 const char *const rk3399_names[] = { "CPU", "GPU" };
210 
211 /* RK3568 conversion table. */
212 const struct rktemp_entry rk3568_temps[] = {
213 	{ -40000, 1584 },
214 	{ -35000, 1620 },
215 	{ -30000, 1652 },
216 	{ -25000, 1688 },
217 	{ -20000, 1720 },
218 	{ -15000, 1756 },
219 	{ -10000, 1788 },
220 	{  -5000, 1824 },
221 	{      0, 1856 },
222 	{   5000, 1892 },
223 	{  10000, 1924 },
224 	{  15000, 1956 },
225 	{  20000, 1992 },
226 	{  25000, 2024 },
227 	{  30000, 2060 },
228 	{  35000, 2092 },
229 	{  40000, 2128 },
230 	{  45000, 2160 },
231 	{  50000, 2196 },
232 	{  55000, 2228 },
233 	{  60000, 2264 },
234 	{  65000, 2300 },
235 	{  70000, 2332 },
236 	{  75000, 2368 },
237 	{  80000, 2400 },
238 	{  85000, 2436 },
239 	{  90000, 2468 },
240 	{  95000, 2500 },
241 	{ 100000, 2536 },
242 	{ 105000, 2572 },
243 	{ 110000, 2604 },
244 	{ 115000, 2636 },
245 	{ 120000, 2672 },
246 	{ 125000, 2704 },
247 };
248 
249 const char *const rk3568_names[] = { "CPU", "GPU" };
250 
251 struct rktemp_softc {
252 	struct device		sc_dev;
253 	bus_space_tag_t		sc_iot;
254 	bus_space_handle_t	sc_ioh;
255 	int			sc_node;
256 
257 	const struct rktemp_entry *sc_temps;
258 	int			sc_ntemps;
259 
260 	struct ksensor		sc_sensors[3];
261 	int			sc_nsensors;
262 	struct ksensordev	sc_sensordev;
263 
264 	struct thermal_sensor	sc_ts;
265 };
266 
267 int	rktemp_match(struct device *, void *, void *);
268 void	rktemp_attach(struct device *, struct device *, void *);
269 
270 const struct cfattach rktemp_ca = {
271 	sizeof (struct rktemp_softc), rktemp_match, rktemp_attach
272 };
273 
274 struct cfdriver rktemp_cd = {
275 	NULL, "rktemp", DV_DULL
276 };
277 
278 void	rktemp_rk3568_init(struct rktemp_softc *);
279 int32_t rktemp_calc_code(struct rktemp_softc *, int32_t);
280 int32_t rktemp_calc_temp(struct rktemp_softc *, int32_t);
281 int	rktemp_valid(struct rktemp_softc *, int32_t);
282 void	rktemp_refresh_sensors(void *);
283 int32_t	rktemp_get_temperature(void *, uint32_t *);
284 
285 int
286 rktemp_match(struct device *parent, void *match, void *aux)
287 {
288 	struct fdt_attach_args *faa = aux;
289 
290 	return (OF_is_compatible(faa->fa_node, "rockchip,rk3288-tsadc") ||
291 	    OF_is_compatible(faa->fa_node, "rockchip,rk3308-tsadc") ||
292 	    OF_is_compatible(faa->fa_node, "rockchip,rk3328-tsadc") ||
293 	    OF_is_compatible(faa->fa_node, "rockchip,rk3399-tsadc") ||
294 	    OF_is_compatible(faa->fa_node, "rockchip,rk3568-tsadc"));
295 }
296 
297 void
298 rktemp_attach(struct device *parent, struct device *self, void *aux)
299 {
300 	struct rktemp_softc *sc = (struct rktemp_softc *)self;
301 	struct fdt_attach_args *faa = aux;
302 	const char *const *names;
303 	uint32_t mode, polarity, temp;
304 	uint32_t auto_con, int_en;
305 	uint32_t inter_pd_soc;
306 	int auto_period, auto_period_ht;
307 	int i;
308 
309 	if (faa->fa_nreg < 1) {
310 		printf(": no registers\n");
311 		return;
312 	}
313 
314 	sc->sc_iot = faa->fa_iot;
315 	sc->sc_node = faa->fa_node;
316 
317 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
318 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
319 		printf(": can't map registers\n");
320 		return;
321 	}
322 
323 	printf("\n");
324 
325 	if (OF_is_compatible(sc->sc_node, "rockchip,rk3288-tsadc")) {
326 		sc->sc_temps = rk3288_temps;
327 		sc->sc_ntemps = nitems(rk3288_temps);
328 		sc->sc_nsensors = 3;
329 		names = rk3288_names;
330 		inter_pd_soc = 13;
331 		auto_period = 250;	/* 250 ms */
332 		auto_period_ht = 50;	/* 50 ms */
333 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3308-tsadc")) {
334 		sc->sc_temps = rk3328_temps;
335 		sc->sc_ntemps = nitems(rk3328_temps);
336 		sc->sc_nsensors = 2;
337 		names = rk3308_names;
338 		inter_pd_soc = 13;
339 		auto_period = 1875;	/* 2.5 ms */
340 		auto_period_ht = 1875;	/* 2.5 ms */
341 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3328-tsadc")) {
342 		sc->sc_temps = rk3328_temps;
343 		sc->sc_ntemps = nitems(rk3328_temps);
344 		sc->sc_nsensors = 1;
345 		names = rk3328_names;
346 		inter_pd_soc = 13;
347 		auto_period = 1875;	/* 2.5 ms */
348 		auto_period_ht = 1875;	/* 2.5 ms */
349 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3399-tsadc")) {
350 		sc->sc_temps = rk3399_temps;
351 		sc->sc_ntemps = nitems(rk3399_temps);
352 		sc->sc_nsensors = 2;
353 		names = rk3399_names;
354 		inter_pd_soc = 13;
355 		auto_period = 1875;	/* 2.5 ms */
356 		auto_period_ht = 1875;	/* 2.5 ms */
357 	} else {
358 		sc->sc_temps = rk3568_temps;
359 		sc->sc_ntemps = nitems(rk3568_temps);
360 		sc->sc_nsensors = 2;
361 		names = rk3568_names;
362 		inter_pd_soc = 63;	/* 97 us */
363 		auto_period = 1622;	/* 2.5 ms */
364 		auto_period_ht = 1622;	/* 2.5 ms */
365 	}
366 
367 	pinctrl_byname(sc->sc_node, "init");
368 
369 	clock_set_assigned(sc->sc_node);
370 	clock_enable(sc->sc_node, "tsadc");
371 	clock_enable(sc->sc_node, "apb_pclk");
372 
373 	/* Reset the TS-ADC controller block. */
374 	reset_assert(sc->sc_node, "tsadc-apb");
375 	delay(10);
376 	reset_deassert(sc->sc_node, "tsadc-apb");
377 
378 	mode = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-mode", 1);
379 	polarity = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-polarity", 0);
380 	temp = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-temp", 95000);
381 
382 	HWRITE4(sc, TSADC_USER_CON,
383 	    inter_pd_soc << TSADC_USER_CON_INTER_PD_SOC_SHIFT);
384 	HWRITE4(sc, TSADC_AUTO_PERIOD, auto_period);
385 	HWRITE4(sc, TSADC_AUTO_PERIOD_HT, auto_period_ht);
386 	HWRITE4(sc, TSADC_HIGHT_INT_DEBOUNCE, 4);
387 	HWRITE4(sc, TSADC_HIGHT_TSHUT_DEBOUNCE, 4);
388 
389 	if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-tsadc"))
390 		rktemp_rk3568_init(sc);
391 
392 	auto_con = HREAD4(sc, TSADC_AUTO_CON);
393 	auto_con |= TSADC_AUTO_CON_TSADC_Q_SEL;
394 	if (polarity)
395 		auto_con |= TSADC_AUTO_CON_TSHUT_POLARITY;
396 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
397 
398 	/* Set shutdown limit. */
399 	for (i = 0; i < sc->sc_nsensors; i++) {
400 		HWRITE4(sc, TSADC_COMP0_SHUT + i * 4,
401 		    rktemp_calc_code(sc, temp));
402 		auto_con |= (TSADC_AUTO_CON_SRC0_EN << i);
403 	}
404 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
405 
406 	/* Clear shutdown output status. */
407 	for (i = 0; i < sc->sc_nsensors; i++)
408 		HWRITE4(sc, TSADC_INT_PD, (TSADC_INT_PD_TSHUT_O_SRC0 << i));
409 
410 	/* Configure mode. */
411 	int_en = HREAD4(sc, TSADC_INT_EN);
412 	for (i = 0; i < sc->sc_nsensors; i++) {
413 		if (mode)
414 			int_en |= (TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0 << i);
415 		else
416 			int_en |= (TSADC_INT_EN_TSHUT_2CRU_EN_SRC0 << i);
417 	}
418 	HWRITE4(sc, TSADC_INT_EN, int_en);
419 
420 	pinctrl_byname(sc->sc_node, "default");
421 
422 	/* Finally turn on the ADC. */
423 	auto_con |= TSADC_AUTO_CON_AUTO_EN;
424 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
425 
426 	/* Register sensors. */
427 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
428 	    sizeof(sc->sc_sensordev.xname));
429 	for (i = 0; i < sc->sc_nsensors; i++) {
430 		strlcpy(sc->sc_sensors[i].desc, names[i],
431 		    sizeof(sc->sc_sensors[i].desc));
432 		sc->sc_sensors[i].type = SENSOR_TEMP;
433 		sc->sc_sensors[i].flags = SENSOR_FINVALID;
434 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
435 	}
436 	sensordev_install(&sc->sc_sensordev);
437 	sensor_task_register(sc, rktemp_refresh_sensors, 5);
438 
439 	sc->sc_ts.ts_node = sc->sc_node;
440 	sc->sc_ts.ts_cookie = sc;
441 	sc->sc_ts.ts_get_temperature = rktemp_get_temperature;
442 	thermal_sensor_register(&sc->sc_ts);
443 }
444 
445 void
446 rktemp_rk3568_init(struct rktemp_softc *sc)
447 {
448 	struct regmap *rm;
449 	uint32_t grf;
450 	int i;
451 
452 	grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0);
453 	rm = regmap_byphandle(grf);
454 	if (rm == 0)
455 		return;
456 
457 	regmap_write_4(rm, RK3568_GRF_TSADC_CON,
458 	    RK3568_GRF_TSADC_EN << 16 | RK3568_GRF_TSADC_EN);
459 	delay(15);
460 	for (i = 0; i <= 2; i++) {
461 		regmap_write_4(rm, RK3568_GRF_TSADC_CON,
462 		    RK3568_GRF_TSADC_ANA_REG(i) << 16 |
463 		    RK3568_GRF_TSADC_ANA_REG(i));
464 	}
465 	delay(100);
466 }
467 
468 int32_t
469 rktemp_calc_code(struct rktemp_softc *sc, int32_t temp)
470 {
471 	const int n = sc->sc_ntemps;
472 	int32_t code0, delta_code;
473 	int32_t temp0, delta_temp;
474 	int i;
475 
476 	if (temp <= sc->sc_temps[0].temp)
477 		return sc->sc_temps[0].code;
478 	if (temp >= sc->sc_temps[n - 1].temp)
479 		return sc->sc_temps[n - 1].code;
480 
481 	for (i = 1; i < n; i++) {
482 		if (temp < sc->sc_temps[i].temp)
483 			break;
484 	}
485 
486 	code0 = sc->sc_temps[i - 1].code;
487 	temp0 = sc->sc_temps[i - 1].temp;
488 	delta_code = sc->sc_temps[i].code - code0;
489 	delta_temp = sc->sc_temps[i].temp - temp0;
490 
491 	return code0 + (temp - temp0) * delta_code / delta_temp;
492 }
493 
494 int32_t
495 rktemp_calc_temp(struct rktemp_softc *sc, int32_t code)
496 {
497 	const int n = sc->sc_ntemps;
498 	int32_t code0, delta_code;
499 	int32_t temp0, delta_temp;
500 	int i;
501 
502 	/* Handle both negative and positive temperature coefficients. */
503 	if (sc->sc_temps[0].code > sc->sc_temps[1].code) {
504 		if (code >= sc->sc_temps[0].code)
505 			return sc->sc_temps[0].code;
506 		if (code <= sc->sc_temps[n - 1].code)
507 			return sc->sc_temps[n - 1].temp;
508 
509 		for (i = 1; i < n; i++) {
510 			if (code > sc->sc_temps[i].code)
511 				break;
512 		}
513 	} else {
514 		if (code <= sc->sc_temps[0].code)
515 			return sc->sc_temps[0].temp;
516 		if (code >= sc->sc_temps[n - 1].code)
517 			return sc->sc_temps[n - 1].temp;
518 
519 		for (i = 1; i < n; i++) {
520 			if (code < sc->sc_temps[i].code)
521 				break;
522 		}
523 	}
524 
525 	code0 = sc->sc_temps[i - 1].code;
526 	temp0 = sc->sc_temps[i - 1].temp;
527 	delta_code = sc->sc_temps[i].code - code0;
528 	delta_temp = sc->sc_temps[i].temp - temp0;
529 
530 	return temp0 + (code - code0) * delta_temp / delta_code;
531 }
532 
533 int
534 rktemp_valid(struct rktemp_softc *sc, int32_t code)
535 {
536 	const int n = sc->sc_ntemps;
537 
538 	if (sc->sc_temps[0].code > sc->sc_temps[1].code) {
539 		if (code > sc->sc_temps[0].code)
540 			return 0;
541 		if (code < sc->sc_temps[n - 1].code)
542 			return 0;
543 	} else {
544 		if (code < sc->sc_temps[0].code)
545 			return 0;
546 		if (code > sc->sc_temps[n - 1].code)
547 			return 0;
548 	}
549 	return 1;
550 }
551 
552 void
553 rktemp_refresh_sensors(void *arg)
554 {
555 	struct rktemp_softc *sc = arg;
556 	int32_t code, temp;
557 	int i;
558 
559 	for (i = 0; i < sc->sc_nsensors; i++) {
560 		code = HREAD4(sc, TSADC_DATA0 + i * 4);
561 		temp = rktemp_calc_temp(sc, code);
562 		sc->sc_sensors[i].value = 273150000 + 1000 * temp;
563 		if (rktemp_valid(sc, code))
564 			sc->sc_sensors[i].flags &= ~SENSOR_FINVALID;
565 		else
566 			sc->sc_sensors[i].flags |= SENSOR_FINVALID;
567 	}
568 }
569 
570 int32_t
571 rktemp_get_temperature(void *cookie, uint32_t *cells)
572 {
573 	struct rktemp_softc *sc = cookie;
574 	uint32_t idx = cells[0];
575 	int32_t code;
576 
577 	if (idx >= sc->sc_nsensors)
578 		return THERMAL_SENSOR_MAX;
579 
580 	code = HREAD4(sc, TSADC_DATA0 + idx * 4);
581 	if (rktemp_valid(sc, code))
582 		return rktemp_calc_temp(sc, code);
583 	else
584 		return THERMAL_SENSOR_MAX;
585 }
586