1/*	$OpenBSD: rktemp.c,v 1.14 2024/06/27 09:40:15 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_SRC_EN(ch)	(1 << ((ch) + 4))
40#define  TSADC_AUTO_CON_TSADC_Q_SEL	(1 << 1)
41#define  TSADC_AUTO_CON_AUTO_EN		(1 << 0)
42#define TSADC_INT_EN			0x0008
43#define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC(ch)	(1 << ((ch) + 8))
44#define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC(ch)	(1 << ((ch) + 4))
45#define TSADC_INT_PD			0x000c
46#define  TSADC_INT_PD_TSHUT_O_SRC(ch)		(1 << ((ch) + 4))
47#define TSADC_DATA(ch)			(0x0020 + (ch) * 4)
48#define TSADC_COMP_INT(ch)		(0x0030 + (ch) * 4)
49#define TSADC_COMP_SHUT(ch)		(0x0040 + (ch) * 4)
50#define TSADC_HIGHT_INT_DEBOUNCE	0x0060
51#define TSADC_HIGHT_TSHUT_DEBOUNCE	0x0064
52#define TSADC_AUTO_PERIOD		0x0068
53#define TSADC_AUTO_PERIOD_HT		0x006c
54
55/* RK3588 */
56#define TSADC_V3_AUTO_SRC		0x000c
57#define  TSADC_V3_AUTO_SRC_CH(ch)	(1 << (ch))
58#define TSADC_V3_HT_INT_EN		0x0014
59#define  TSADC_V3_HT_INT_EN_CH(ch)	(1 << (ch))
60#define TSADC_V3_GPIO_EN		0x0018
61#define  TSADC_V3_GPIO_EN_CH(ch)	(1 << (ch))
62#define TSADC_V3_CRU_EN			0x001c
63#define  TSADC_V3_CRU_EN_CH(ch)		(1 << (ch))
64#define TSADC_V3_HLT_INT_PD		0x0024
65#define  TSADC_V3_HT_INT_STATUS(ch)	(1 << (ch))
66#define TSADC_V3_DATA(ch)		(0x002c + (ch) * 4)
67#define TSADC_V3_COMP_INT(ch)		(0x006c + (ch) * 4)
68#define TSADC_V3_COMP_SHUT(ch)		(0x010c + (ch) * 4)
69#define TSADC_V3_HIGHT_INT_DEBOUNCE	0x014c
70#define TSADC_V3_HIGHT_TSHUT_DEBOUNCE	0x0150
71#define TSADC_V3_AUTO_PERIOD		0x0154
72#define TSADC_V3_AUTO_PERIOD_HT		0x0158
73
74/* RK3568 */
75#define RK3568_GRF_TSADC_CON		0x0600
76#define  RK3568_GRF_TSADC_EN		(1 << 8)
77#define  RK3568_GRF_TSADC_ANA_REG(idx)	(1 << (idx))
78
79#define HREAD4(sc, reg)							\
80	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
81#define HWRITE4(sc, reg, val)						\
82	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
83
84struct rktemp_entry {
85	int32_t temp;
86	int32_t code;
87};
88
89/* RK3288 conversion table. */
90const struct rktemp_entry rk3288_temps[] = {
91	{ -40000, 3800 },
92	{ -35000, 3792 },
93	{ -30000, 3783 },
94	{ -25000, 3774 },
95	{ -20000, 3765 },
96	{ -15000, 3756 },
97	{ -10000, 3747 },
98	{  -5000, 3737 },
99	{      0, 3728 },
100	{   5000, 3718 },
101	{  10000, 3708 },
102	{  15000, 3698 },
103	{  20000, 3688 },
104	{  25000, 3678 },
105	{  30000, 3667 },
106	{  35000, 3656 },
107	{  40000, 3645 },
108	{  45000, 3634 },
109	{  50000, 3623 },
110	{  55000, 3611 },
111	{  60000, 3600 },
112	{  65000, 3588 },
113	{  70000, 3575 },
114	{  75000, 3563 },
115	{  80000, 3550 },
116	{  85000, 3537 },
117	{  90000, 3524 },
118	{  95000, 3510 },
119	{ 100000, 3496 },
120	{ 105000, 3482 },
121	{ 110000, 3467 },
122	{ 115000, 3452 },
123	{ 120000, 3437 },
124	{ 125000, 3421 },
125};
126
127const char *const rk3288_names[] = { "", "CPU", "GPU" };
128
129/* RK3328 conversion table. */
130const struct rktemp_entry rk3328_temps[] = {
131	{ -40000, 296 },
132	{ -35000, 304 },
133	{ -30000, 313 },
134	{ -20000, 331 },
135	{ -15000, 340 },
136	{ -10000, 349 },
137	{  -5000, 359 },
138	{      0, 368 },
139	{   5000, 378 },
140	{  10000, 388 },
141	{  15000, 398 },
142	{  20000, 408 },
143	{  25000, 418 },
144	{  30000, 429 },
145	{  35000, 440 },
146	{  40000, 451 },
147	{  45000, 462 },
148	{  50000, 473 },
149	{  55000, 485 },
150	{  60000, 496 },
151	{  65000, 508 },
152	{  70000, 521 },
153	{  75000, 533 },
154	{  80000, 546 },
155	{  85000, 559 },
156	{  90000, 572 },
157	{  95000, 586 },
158	{ 100000, 600 },
159	{ 105000, 614 },
160	{ 110000, 629 },
161	{ 115000, 644 },
162	{ 120000, 659 },
163	{ 125000, 675 },
164};
165
166const char *const rk3308_names[] = { "CPU", "GPU" };
167const char *const rk3328_names[] = { "CPU" };
168
169/* RK3399 conversion table. */
170const struct rktemp_entry rk3399_temps[] = {
171	{ -40000, 402 },
172	{ -35000, 410 },
173	{ -30000, 419 },
174	{ -25000, 427 },
175	{ -20000, 436 },
176	{ -15000, 444 },
177	{ -10000, 453 },
178	{  -5000, 461 },
179	{      0, 470 },
180	{   5000, 478 },
181	{  10000, 487 },
182	{  15000, 496 },
183	{  20000, 504 },
184	{  25000, 513 },
185	{  30000, 521 },
186	{  35000, 530 },
187	{  40000, 538 },
188	{  45000, 547 },
189	{  50000, 555 },
190	{  55000, 564 },
191	{  60000, 573 },
192	{  65000, 581 },
193	{  70000, 590 },
194	{  75000, 599 },
195	{  80000, 607 },
196	{  85000, 616 },
197	{  90000, 624 },
198	{  95000, 633 },
199	{ 100000, 642 },
200	{ 105000, 650 },
201	{ 110000, 659 },
202	{ 115000, 668 },
203	{ 120000, 677 },
204	{ 125000, 685 },
205};
206
207const char *const rk3399_names[] = { "CPU", "GPU" };
208
209/* RK3568 conversion table. */
210const struct rktemp_entry rk3568_temps[] = {
211	{ -40000, 1584 },
212	{ -35000, 1620 },
213	{ -30000, 1652 },
214	{ -25000, 1688 },
215	{ -20000, 1720 },
216	{ -15000, 1756 },
217	{ -10000, 1788 },
218	{  -5000, 1824 },
219	{      0, 1856 },
220	{   5000, 1892 },
221	{  10000, 1924 },
222	{  15000, 1956 },
223	{  20000, 1992 },
224	{  25000, 2024 },
225	{  30000, 2060 },
226	{  35000, 2092 },
227	{  40000, 2128 },
228	{  45000, 2160 },
229	{  50000, 2196 },
230	{  55000, 2228 },
231	{  60000, 2264 },
232	{  65000, 2300 },
233	{  70000, 2332 },
234	{  75000, 2368 },
235	{  80000, 2400 },
236	{  85000, 2436 },
237	{  90000, 2468 },
238	{  95000, 2500 },
239	{ 100000, 2536 },
240	{ 105000, 2572 },
241	{ 110000, 2604 },
242	{ 115000, 2636 },
243	{ 120000, 2672 },
244	{ 125000, 2704 },
245};
246
247const char *const rk3568_names[] = { "CPU", "GPU" };
248
249/* RK3588 conversion table. */
250const struct rktemp_entry rk3588_temps[] = {
251	{ -40000, 215 },
252	{  25000, 285 },
253	{  85000, 350 },
254	{ 125000, 395 },
255};
256
257const char *const rk3588_names[] = {
258	"Top",
259	"CPU (big0)",
260	"CPU (big1)",
261	"CPU (little)",
262	"Center",
263	"GPU",
264	"NPU"
265};
266
267struct rktemp_softc {
268	struct device		sc_dev;
269	bus_space_tag_t		sc_iot;
270	bus_space_handle_t	sc_ioh;
271	int			sc_node;
272	void			*sc_ih;
273
274	bus_size_t		sc_data0;
275
276	const struct rktemp_entry *sc_temps;
277	int			sc_ntemps;
278
279	struct ksensor		sc_sensors[7];
280	int			sc_nsensors;
281	struct ksensordev	sc_sensordev;
282
283	struct thermal_sensor	sc_ts;
284};
285
286int	rktemp_match(struct device *, void *, void *);
287void	rktemp_attach(struct device *, struct device *, void *);
288
289const struct cfattach rktemp_ca = {
290	sizeof (struct rktemp_softc), rktemp_match, rktemp_attach
291};
292
293struct cfdriver rktemp_cd = {
294	NULL, "rktemp", DV_DULL
295};
296
297int	rktemp_intr(void *);
298void	rktemp_rk3568_init(struct rktemp_softc *);
299int32_t rktemp_calc_code(struct rktemp_softc *, int32_t);
300int32_t rktemp_calc_temp(struct rktemp_softc *, int32_t);
301int	rktemp_valid(struct rktemp_softc *, int32_t);
302void	rktemp_refresh_sensors(void *);
303int32_t	rktemp_get_temperature(void *, uint32_t *);
304int	rktemp_set_limit(void *, uint32_t *, uint32_t);
305
306int
307rktemp_match(struct device *parent, void *match, void *aux)
308{
309	struct fdt_attach_args *faa = aux;
310
311	return (OF_is_compatible(faa->fa_node, "rockchip,rk3288-tsadc") ||
312	    OF_is_compatible(faa->fa_node, "rockchip,rk3308-tsadc") ||
313	    OF_is_compatible(faa->fa_node, "rockchip,rk3328-tsadc") ||
314	    OF_is_compatible(faa->fa_node, "rockchip,rk3399-tsadc") ||
315	    OF_is_compatible(faa->fa_node, "rockchip,rk3568-tsadc") ||
316	    OF_is_compatible(faa->fa_node, "rockchip,rk3588-tsadc"));
317}
318
319void
320rktemp_attach(struct device *parent, struct device *self, void *aux)
321{
322	struct rktemp_softc *sc = (struct rktemp_softc *)self;
323	struct fdt_attach_args *faa = aux;
324	const char *const *names;
325	uint32_t mode, polarity, temp;
326	uint32_t auto_con, inter_pd_soc;
327	int auto_period, auto_period_ht;
328	int i;
329
330	if (faa->fa_nreg < 1) {
331		printf(": no registers\n");
332		return;
333	}
334
335	sc->sc_iot = faa->fa_iot;
336	sc->sc_node = faa->fa_node;
337
338	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
339	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
340		printf(": can't map registers\n");
341		return;
342	}
343
344	if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-tsadc")) {
345		sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_SOFTCLOCK,
346		    rktemp_intr, sc, sc->sc_dev.dv_xname);
347		if (sc->sc_ih == NULL) {
348			printf(": can't establish interrupt\n");
349			return;
350		}
351	}
352
353	printf("\n");
354
355	if (OF_is_compatible(sc->sc_node, "rockchip,rk3288-tsadc")) {
356		sc->sc_temps = rk3288_temps;
357		sc->sc_ntemps = nitems(rk3288_temps);
358		sc->sc_nsensors = 3;
359		names = rk3288_names;
360		inter_pd_soc = 13;
361		auto_period = 250;	/* 250 ms */
362		auto_period_ht = 50;	/* 50 ms */
363	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3308-tsadc")) {
364		sc->sc_temps = rk3328_temps;
365		sc->sc_ntemps = nitems(rk3328_temps);
366		sc->sc_nsensors = 2;
367		names = rk3308_names;
368		inter_pd_soc = 13;
369		auto_period = 1875;	/* 2.5 ms */
370		auto_period_ht = 1875;	/* 2.5 ms */
371	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3328-tsadc")) {
372		sc->sc_temps = rk3328_temps;
373		sc->sc_ntemps = nitems(rk3328_temps);
374		sc->sc_nsensors = 1;
375		names = rk3328_names;
376		inter_pd_soc = 13;
377		auto_period = 1875;	/* 2.5 ms */
378		auto_period_ht = 1875;	/* 2.5 ms */
379	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3399-tsadc")) {
380		sc->sc_temps = rk3399_temps;
381		sc->sc_ntemps = nitems(rk3399_temps);
382		sc->sc_nsensors = 2;
383		names = rk3399_names;
384		inter_pd_soc = 13;
385		auto_period = 1875;	/* 2.5 ms */
386		auto_period_ht = 1875;	/* 2.5 ms */
387	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-tsadc")) {
388		sc->sc_temps = rk3568_temps;
389		sc->sc_ntemps = nitems(rk3568_temps);
390		sc->sc_nsensors = 2;
391		names = rk3568_names;
392		inter_pd_soc = 63;	/* 97 us */
393		auto_period = 1622;	/* 2.5 ms */
394		auto_period_ht = 1622;	/* 2.5 ms */
395	} else {
396		sc->sc_temps = rk3588_temps;
397		sc->sc_ntemps = nitems(rk3588_temps);
398		sc->sc_nsensors = 7;
399		names = rk3588_names;
400		inter_pd_soc = 0;
401		auto_period = 5000;	/* 2.5 ms */
402		auto_period_ht = 5000;	/* 2.5 ms */
403	}
404
405	pinctrl_byname(sc->sc_node, "init");
406
407	clock_set_assigned(sc->sc_node);
408	clock_enable(sc->sc_node, "tsadc");
409	clock_enable(sc->sc_node, "apb_pclk");
410
411	/* Reset the TS-ADC controller block. */
412	reset_assert_all(sc->sc_node);
413	delay(10);
414	reset_deassert_all(sc->sc_node);
415
416	mode = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-mode", 1);
417	polarity = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-polarity", 0);
418	temp = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-temp", 95000);
419
420	if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-tsadc")) {
421		uint32_t gpio_en, cru_en;
422
423		sc->sc_data0 = TSADC_V3_DATA(0);
424
425		HWRITE4(sc, TSADC_V3_AUTO_PERIOD, auto_period);
426		HWRITE4(sc, TSADC_V3_AUTO_PERIOD_HT, auto_period_ht);
427		HWRITE4(sc, TSADC_V3_HIGHT_INT_DEBOUNCE, 4);
428		HWRITE4(sc, TSADC_V3_HIGHT_TSHUT_DEBOUNCE, 4);
429
430		auto_con = TSADC_AUTO_CON_TSHUT_POLARITY << 16;
431		if (polarity)
432			auto_con = TSADC_AUTO_CON_TSHUT_POLARITY;
433		HWRITE4(sc, TSADC_AUTO_CON, auto_con);
434
435		/* Set shutdown limit. */
436		for (i = 0; i < sc->sc_nsensors; i++) {
437			HWRITE4(sc, TSADC_V3_COMP_SHUT(i),
438			    rktemp_calc_code(sc, temp));
439			HWRITE4(sc, TSADC_V3_AUTO_SRC,
440			    TSADC_V3_AUTO_SRC_CH(i) << 16 |
441			    TSADC_V3_AUTO_SRC_CH(i));
442		}
443
444		/* Clear shutdown output status. */
445		for (i = 0; i < sc->sc_nsensors; i++) {
446			HWRITE4(sc, TSADC_V3_HLT_INT_PD,
447			    TSADC_V3_HT_INT_STATUS(i));
448		}
449
450		/* Configure mode. */
451		gpio_en = cru_en = 0;
452		for (i = 0; i < sc->sc_nsensors; i++) {
453			gpio_en |= TSADC_V3_GPIO_EN_CH(i) << 16;
454			cru_en |= TSADC_V3_CRU_EN_CH(i) << 16;
455			if (mode)
456				gpio_en |= TSADC_V3_GPIO_EN_CH(i);
457			else
458				cru_en |= TSADC_V3_CRU_EN_CH(i);
459		}
460		HWRITE4(sc, TSADC_V3_GPIO_EN, gpio_en);
461		HWRITE4(sc, TSADC_V3_CRU_EN, cru_en);
462	} else {
463		uint32_t int_en;
464
465		sc->sc_data0 = TSADC_DATA(0);
466
467		HWRITE4(sc, TSADC_USER_CON,
468		    inter_pd_soc << TSADC_USER_CON_INTER_PD_SOC_SHIFT);
469		HWRITE4(sc, TSADC_AUTO_PERIOD, auto_period);
470		HWRITE4(sc, TSADC_AUTO_PERIOD_HT, auto_period_ht);
471		HWRITE4(sc, TSADC_HIGHT_INT_DEBOUNCE, 4);
472		HWRITE4(sc, TSADC_HIGHT_TSHUT_DEBOUNCE, 4);
473
474		if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-tsadc"))
475			rktemp_rk3568_init(sc);
476
477		auto_con = HREAD4(sc, TSADC_AUTO_CON);
478		auto_con |= TSADC_AUTO_CON_TSADC_Q_SEL;
479		if (polarity)
480			auto_con |= TSADC_AUTO_CON_TSHUT_POLARITY;
481		HWRITE4(sc, TSADC_AUTO_CON, auto_con);
482
483		/* Set shutdown limit. */
484		for (i = 0; i < sc->sc_nsensors; i++) {
485			HWRITE4(sc, TSADC_COMP_SHUT(i),
486			    rktemp_calc_code(sc, temp));
487			auto_con |= (TSADC_AUTO_CON_SRC_EN(i));
488		}
489		HWRITE4(sc, TSADC_AUTO_CON, auto_con);
490
491		/* Clear shutdown output status. */
492		for (i = 0; i < sc->sc_nsensors; i++)
493			HWRITE4(sc, TSADC_INT_PD, TSADC_INT_PD_TSHUT_O_SRC(i));
494
495		/* Configure mode. */
496		int_en = HREAD4(sc, TSADC_INT_EN);
497		for (i = 0; i < sc->sc_nsensors; i++) {
498			if (mode)
499				int_en |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC(i);
500			else
501				int_en |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC(i);
502		}
503		HWRITE4(sc, TSADC_INT_EN, int_en);
504	}
505
506	pinctrl_byname(sc->sc_node, "default");
507
508	/* Finally turn on the ADC. */
509	if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-tsadc")) {
510		HWRITE4(sc, TSADC_AUTO_CON,
511		    TSADC_AUTO_CON_AUTO_EN << 16 | TSADC_AUTO_CON_AUTO_EN);
512	} else {
513		auto_con |= TSADC_AUTO_CON_AUTO_EN;
514		HWRITE4(sc, TSADC_AUTO_CON, auto_con);
515	}
516
517	/* Register sensors. */
518	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
519	    sizeof(sc->sc_sensordev.xname));
520	for (i = 0; i < sc->sc_nsensors; i++) {
521		strlcpy(sc->sc_sensors[i].desc, names[i],
522		    sizeof(sc->sc_sensors[i].desc));
523		sc->sc_sensors[i].type = SENSOR_TEMP;
524		sc->sc_sensors[i].flags = SENSOR_FINVALID;
525		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
526	}
527	sensordev_install(&sc->sc_sensordev);
528	sensor_task_register(sc, rktemp_refresh_sensors, 5);
529
530	sc->sc_ts.ts_node = sc->sc_node;
531	sc->sc_ts.ts_cookie = sc;
532	sc->sc_ts.ts_get_temperature = rktemp_get_temperature;
533	if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-tsadc"))
534		sc->sc_ts.ts_set_limit = rktemp_set_limit;
535	thermal_sensor_register(&sc->sc_ts);
536}
537
538int
539rktemp_intr(void *arg)
540{
541	struct rktemp_softc *sc = arg;
542	uint32_t stat, ch;
543
544	stat = HREAD4(sc, TSADC_V3_HLT_INT_PD);
545	stat &= HREAD4(sc, TSADC_V3_HT_INT_EN);
546	for (ch = 0; ch < sc->sc_nsensors; ch++) {
547		if (stat & TSADC_V3_HT_INT_STATUS(ch))
548			thermal_sensor_update(&sc->sc_ts, &ch);
549	}
550
551	/*
552	 * Disable and clear the active interrupts.  The thermal zone
553	 * code will set a new limit when necessary.
554	 */
555	HWRITE4(sc, TSADC_V3_HT_INT_EN, stat << 16);
556	HWRITE4(sc, TSADC_V3_HLT_INT_PD, stat);
557
558	return 1;
559}
560
561void
562rktemp_rk3568_init(struct rktemp_softc *sc)
563{
564	struct regmap *rm;
565	uint32_t grf;
566	int i;
567
568	grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0);
569	rm = regmap_byphandle(grf);
570	if (rm == 0)
571		return;
572
573	regmap_write_4(rm, RK3568_GRF_TSADC_CON,
574	    RK3568_GRF_TSADC_EN << 16 | RK3568_GRF_TSADC_EN);
575	delay(15);
576	for (i = 0; i <= 2; i++) {
577		regmap_write_4(rm, RK3568_GRF_TSADC_CON,
578		    RK3568_GRF_TSADC_ANA_REG(i) << 16 |
579		    RK3568_GRF_TSADC_ANA_REG(i));
580	}
581	delay(100);
582}
583
584int32_t
585rktemp_calc_code(struct rktemp_softc *sc, int32_t temp)
586{
587	const int n = sc->sc_ntemps;
588	int32_t code0, delta_code;
589	int32_t temp0, delta_temp;
590	int i;
591
592	if (temp <= sc->sc_temps[0].temp)
593		return sc->sc_temps[0].code;
594	if (temp >= sc->sc_temps[n - 1].temp)
595		return sc->sc_temps[n - 1].code;
596
597	for (i = 1; i < n; i++) {
598		if (temp < sc->sc_temps[i].temp)
599			break;
600	}
601
602	code0 = sc->sc_temps[i - 1].code;
603	temp0 = sc->sc_temps[i - 1].temp;
604	delta_code = sc->sc_temps[i].code - code0;
605	delta_temp = sc->sc_temps[i].temp - temp0;
606
607	return code0 + (temp - temp0) * delta_code / delta_temp;
608}
609
610int32_t
611rktemp_calc_temp(struct rktemp_softc *sc, int32_t code)
612{
613	const int n = sc->sc_ntemps;
614	int32_t code0, delta_code;
615	int32_t temp0, delta_temp;
616	int i;
617
618	/* Handle both negative and positive temperature coefficients. */
619	if (sc->sc_temps[0].code > sc->sc_temps[1].code) {
620		if (code >= sc->sc_temps[0].code)
621			return sc->sc_temps[0].code;
622		if (code <= sc->sc_temps[n - 1].code)
623			return sc->sc_temps[n - 1].temp;
624
625		for (i = 1; i < n; i++) {
626			if (code > sc->sc_temps[i].code)
627				break;
628		}
629	} else {
630		if (code <= sc->sc_temps[0].code)
631			return sc->sc_temps[0].temp;
632		if (code >= sc->sc_temps[n - 1].code)
633			return sc->sc_temps[n - 1].temp;
634
635		for (i = 1; i < n; i++) {
636			if (code < sc->sc_temps[i].code)
637				break;
638		}
639	}
640
641	code0 = sc->sc_temps[i - 1].code;
642	temp0 = sc->sc_temps[i - 1].temp;
643	delta_code = sc->sc_temps[i].code - code0;
644	delta_temp = sc->sc_temps[i].temp - temp0;
645
646	return temp0 + (code - code0) * delta_temp / delta_code;
647}
648
649int
650rktemp_valid(struct rktemp_softc *sc, int32_t code)
651{
652	const int n = sc->sc_ntemps;
653
654	if (sc->sc_temps[0].code > sc->sc_temps[1].code) {
655		if (code > sc->sc_temps[0].code)
656			return 0;
657		if (code < sc->sc_temps[n - 1].code)
658			return 0;
659	} else {
660		if (code < sc->sc_temps[0].code)
661			return 0;
662		if (code > sc->sc_temps[n - 1].code)
663			return 0;
664	}
665	return 1;
666}
667
668void
669rktemp_refresh_sensors(void *arg)
670{
671	struct rktemp_softc *sc = arg;
672	int32_t code, temp;
673	int i;
674
675	for (i = 0; i < sc->sc_nsensors; i++) {
676		code = HREAD4(sc, sc->sc_data0 + (i * 4));
677		temp = rktemp_calc_temp(sc, code);
678		sc->sc_sensors[i].value = 273150000 + 1000 * temp;
679		if (rktemp_valid(sc, code))
680			sc->sc_sensors[i].flags &= ~SENSOR_FINVALID;
681		else
682			sc->sc_sensors[i].flags |= SENSOR_FINVALID;
683	}
684}
685
686int32_t
687rktemp_get_temperature(void *cookie, uint32_t *cells)
688{
689	struct rktemp_softc *sc = cookie;
690	uint32_t ch = cells[0];
691	int32_t code;
692
693	if (ch >= sc->sc_nsensors)
694		return THERMAL_SENSOR_MAX;
695
696	code = HREAD4(sc, sc->sc_data0 + (ch * 4));
697	if (rktemp_valid(sc, code))
698		return rktemp_calc_temp(sc, code);
699	else
700		return THERMAL_SENSOR_MAX;
701}
702
703int
704rktemp_set_limit(void *cookie, uint32_t *cells, uint32_t temp)
705{
706	struct rktemp_softc *sc = cookie;
707	uint32_t ch = cells[0];
708
709	if (ch >= sc->sc_nsensors)
710		return ENXIO;
711
712	/* Set limit for this sensor. */
713	HWRITE4(sc, TSADC_V3_COMP_INT(ch), rktemp_calc_code(sc, temp));
714
715	/* Clear and enable the corresponding interrupt. */
716	HWRITE4(sc, TSADC_V3_HLT_INT_PD, TSADC_V3_HT_INT_STATUS(ch));
717	HWRITE4(sc, TSADC_V3_HT_INT_EN, TSADC_V3_HT_INT_EN_CH(ch) << 16 |
718	    TSADC_V3_HT_INT_EN_CH(ch));
719
720	return 0;
721}
722