xref: /openbsd-src/sys/dev/fdt/rktemp.c (revision 74b3eef0805cd8f8db37988c9b4d4ca9647e622e)
1*74b3eef0Skettenis /*	$OpenBSD: rktemp.c,v 1.14 2024/06/27 09:40:15 kettenis Exp $	*/
293ab5de6Skettenis /*
393ab5de6Skettenis  * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org>
493ab5de6Skettenis  *
593ab5de6Skettenis  * Permission to use, copy, modify, and distribute this software for any
693ab5de6Skettenis  * purpose with or without fee is hereby granted, provided that the above
793ab5de6Skettenis  * copyright notice and this permission notice appear in all copies.
893ab5de6Skettenis  *
993ab5de6Skettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1093ab5de6Skettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1193ab5de6Skettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1293ab5de6Skettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1393ab5de6Skettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1493ab5de6Skettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1593ab5de6Skettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1693ab5de6Skettenis  */
1793ab5de6Skettenis 
1893ab5de6Skettenis #include <sys/param.h>
1993ab5de6Skettenis #include <sys/systm.h>
2093ab5de6Skettenis #include <sys/device.h>
2193ab5de6Skettenis #include <sys/sensors.h>
2293ab5de6Skettenis 
2393ab5de6Skettenis #include <machine/intr.h>
2493ab5de6Skettenis #include <machine/bus.h>
2593ab5de6Skettenis #include <machine/fdt.h>
2693ab5de6Skettenis 
2793ab5de6Skettenis #include <dev/ofw/openfirm.h>
2893ab5de6Skettenis #include <dev/ofw/ofw_clock.h>
2993ab5de6Skettenis #include <dev/ofw/ofw_misc.h>
3093ab5de6Skettenis #include <dev/ofw/ofw_pinctrl.h>
3138041c6dSkettenis #include <dev/ofw/ofw_thermal.h>
3293ab5de6Skettenis #include <dev/ofw/fdt.h>
3393ab5de6Skettenis 
3493ab5de6Skettenis /* Registers */
3593ab5de6Skettenis #define TSADC_USER_CON			0x0000
361d1e9e74Skettenis #define  TSADC_USER_CON_INTER_PD_SOC_SHIFT	6
3793ab5de6Skettenis #define TSADC_AUTO_CON			0x0004
3893ab5de6Skettenis #define  TSADC_AUTO_CON_TSHUT_POLARITY	(1 << 8)
39f126f9b0Skettenis #define  TSADC_AUTO_CON_SRC_EN(ch)	(1 << ((ch) + 4))
4093ab5de6Skettenis #define  TSADC_AUTO_CON_TSADC_Q_SEL	(1 << 1)
4193ab5de6Skettenis #define  TSADC_AUTO_CON_AUTO_EN		(1 << 0)
4293ab5de6Skettenis #define TSADC_INT_EN			0x0008
43f126f9b0Skettenis #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC(ch)	(1 << ((ch) + 8))
44f126f9b0Skettenis #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC(ch)	(1 << ((ch) + 4))
4593ab5de6Skettenis #define TSADC_INT_PD			0x000c
46f126f9b0Skettenis #define  TSADC_INT_PD_TSHUT_O_SRC(ch)		(1 << ((ch) + 4))
47f126f9b0Skettenis #define TSADC_DATA(ch)			(0x0020 + (ch) * 4)
48f126f9b0Skettenis #define TSADC_COMP_INT(ch)		(0x0030 + (ch) * 4)
49f126f9b0Skettenis #define TSADC_COMP_SHUT(ch)		(0x0040 + (ch) * 4)
501d1e9e74Skettenis #define TSADC_HIGHT_INT_DEBOUNCE	0x0060
511d1e9e74Skettenis #define TSADC_HIGHT_TSHUT_DEBOUNCE	0x0064
5293ab5de6Skettenis #define TSADC_AUTO_PERIOD		0x0068
5393ab5de6Skettenis #define TSADC_AUTO_PERIOD_HT		0x006c
5493ab5de6Skettenis 
55f126f9b0Skettenis /* RK3588 */
56f126f9b0Skettenis #define TSADC_V3_AUTO_SRC		0x000c
57f126f9b0Skettenis #define  TSADC_V3_AUTO_SRC_CH(ch)	(1 << (ch))
58*74b3eef0Skettenis #define TSADC_V3_HT_INT_EN		0x0014
59*74b3eef0Skettenis #define  TSADC_V3_HT_INT_EN_CH(ch)	(1 << (ch))
60f126f9b0Skettenis #define TSADC_V3_GPIO_EN		0x0018
61f126f9b0Skettenis #define  TSADC_V3_GPIO_EN_CH(ch)	(1 << (ch))
62f126f9b0Skettenis #define TSADC_V3_CRU_EN			0x001c
63f126f9b0Skettenis #define  TSADC_V3_CRU_EN_CH(ch)		(1 << (ch))
64f126f9b0Skettenis #define TSADC_V3_HLT_INT_PD		0x0024
65f126f9b0Skettenis #define  TSADC_V3_HT_INT_STATUS(ch)	(1 << (ch))
66f126f9b0Skettenis #define TSADC_V3_DATA(ch)		(0x002c + (ch) * 4)
67*74b3eef0Skettenis #define TSADC_V3_COMP_INT(ch)		(0x006c + (ch) * 4)
68f126f9b0Skettenis #define TSADC_V3_COMP_SHUT(ch)		(0x010c + (ch) * 4)
69f126f9b0Skettenis #define TSADC_V3_HIGHT_INT_DEBOUNCE	0x014c
70f126f9b0Skettenis #define TSADC_V3_HIGHT_TSHUT_DEBOUNCE	0x0150
71f126f9b0Skettenis #define TSADC_V3_AUTO_PERIOD		0x0154
72f126f9b0Skettenis #define TSADC_V3_AUTO_PERIOD_HT		0x0158
73f126f9b0Skettenis 
741d1e9e74Skettenis /* RK3568 */
751d1e9e74Skettenis #define RK3568_GRF_TSADC_CON		0x0600
761d1e9e74Skettenis #define  RK3568_GRF_TSADC_EN		(1 << 8)
771d1e9e74Skettenis #define  RK3568_GRF_TSADC_ANA_REG(idx)	(1 << (idx))
781d1e9e74Skettenis 
7993ab5de6Skettenis #define HREAD4(sc, reg)							\
8093ab5de6Skettenis 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
8193ab5de6Skettenis #define HWRITE4(sc, reg, val)						\
8293ab5de6Skettenis 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
8393ab5de6Skettenis 
849b6a9f2aSkettenis struct rktemp_entry {
8593ab5de6Skettenis 	int32_t temp;
869b6a9f2aSkettenis 	int32_t code;
8793ab5de6Skettenis };
8893ab5de6Skettenis 
899b6a9f2aSkettenis /* RK3288 conversion table. */
9037c734d3Snaddy const struct rktemp_entry rk3288_temps[] = {
919b6a9f2aSkettenis 	{ -40000, 3800 },
929b6a9f2aSkettenis 	{ -35000, 3792 },
939b6a9f2aSkettenis 	{ -30000, 3783 },
949b6a9f2aSkettenis 	{ -25000, 3774 },
959b6a9f2aSkettenis 	{ -20000, 3765 },
969b6a9f2aSkettenis 	{ -15000, 3756 },
979b6a9f2aSkettenis 	{ -10000, 3747 },
989b6a9f2aSkettenis 	{  -5000, 3737 },
999b6a9f2aSkettenis 	{      0, 3728 },
1009b6a9f2aSkettenis 	{   5000, 3718 },
1019b6a9f2aSkettenis 	{  10000, 3708 },
1029b6a9f2aSkettenis 	{  15000, 3698 },
1039b6a9f2aSkettenis 	{  20000, 3688 },
1049b6a9f2aSkettenis 	{  25000, 3678 },
1059b6a9f2aSkettenis 	{  30000, 3667 },
1069b6a9f2aSkettenis 	{  35000, 3656 },
1079b6a9f2aSkettenis 	{  40000, 3645 },
1089b6a9f2aSkettenis 	{  45000, 3634 },
1099b6a9f2aSkettenis 	{  50000, 3623 },
1109b6a9f2aSkettenis 	{  55000, 3611 },
1119b6a9f2aSkettenis 	{  60000, 3600 },
1129b6a9f2aSkettenis 	{  65000, 3588 },
1139b6a9f2aSkettenis 	{  70000, 3575 },
1149b6a9f2aSkettenis 	{  75000, 3563 },
1159b6a9f2aSkettenis 	{  80000, 3550 },
1169b6a9f2aSkettenis 	{  85000, 3537 },
1179b6a9f2aSkettenis 	{  90000, 3524 },
1189b6a9f2aSkettenis 	{  95000, 3510 },
1199b6a9f2aSkettenis 	{ 100000, 3496 },
1209b6a9f2aSkettenis 	{ 105000, 3482 },
1219b6a9f2aSkettenis 	{ 110000, 3467 },
1229b6a9f2aSkettenis 	{ 115000, 3452 },
1239b6a9f2aSkettenis 	{ 120000, 3437 },
1249b6a9f2aSkettenis 	{ 125000, 3421 },
1259b6a9f2aSkettenis };
1269b6a9f2aSkettenis 
12737c734d3Snaddy const char *const rk3288_names[] = { "", "CPU", "GPU" };
1289b6a9f2aSkettenis 
129bbd23df1Skettenis /* RK3328 conversion table. */
13037c734d3Snaddy const struct rktemp_entry rk3328_temps[] = {
131bbd23df1Skettenis 	{ -40000, 296 },
132bbd23df1Skettenis 	{ -35000, 304 },
133bbd23df1Skettenis 	{ -30000, 313 },
134bbd23df1Skettenis 	{ -20000, 331 },
135bbd23df1Skettenis 	{ -15000, 340 },
136bbd23df1Skettenis 	{ -10000, 349 },
137bbd23df1Skettenis 	{  -5000, 359 },
138bbd23df1Skettenis 	{      0, 368 },
139bbd23df1Skettenis 	{   5000, 378 },
140bbd23df1Skettenis 	{  10000, 388 },
141bbd23df1Skettenis 	{  15000, 398 },
142bbd23df1Skettenis 	{  20000, 408 },
143bbd23df1Skettenis 	{  25000, 418 },
144bbd23df1Skettenis 	{  30000, 429 },
145bbd23df1Skettenis 	{  35000, 440 },
146bbd23df1Skettenis 	{  40000, 451 },
147bbd23df1Skettenis 	{  45000, 462 },
148bbd23df1Skettenis 	{  50000, 473 },
149bbd23df1Skettenis 	{  55000, 485 },
150bbd23df1Skettenis 	{  60000, 496 },
151bbd23df1Skettenis 	{  65000, 508 },
152bbd23df1Skettenis 	{  70000, 521 },
153bbd23df1Skettenis 	{  75000, 533 },
154bbd23df1Skettenis 	{  80000, 546 },
155bbd23df1Skettenis 	{  85000, 559 },
156bbd23df1Skettenis 	{  90000, 572 },
157bbd23df1Skettenis 	{  95000, 586 },
158bbd23df1Skettenis 	{ 100000, 600 },
159bbd23df1Skettenis 	{ 105000, 614 },
160bbd23df1Skettenis 	{ 110000, 629 },
161bbd23df1Skettenis 	{ 115000, 644 },
162bbd23df1Skettenis 	{ 120000, 659 },
163bbd23df1Skettenis 	{ 125000, 675 },
164bbd23df1Skettenis };
165bbd23df1Skettenis 
16637c734d3Snaddy const char *const rk3308_names[] = { "CPU", "GPU" };
16737c734d3Snaddy const char *const rk3328_names[] = { "CPU" };
168bbd23df1Skettenis 
16993ab5de6Skettenis /* RK3399 conversion table. */
17037c734d3Snaddy const struct rktemp_entry rk3399_temps[] = {
17193ab5de6Skettenis 	{ -40000, 402 },
17293ab5de6Skettenis 	{ -35000, 410 },
17393ab5de6Skettenis 	{ -30000, 419 },
17493ab5de6Skettenis 	{ -25000, 427 },
17593ab5de6Skettenis 	{ -20000, 436 },
17693ab5de6Skettenis 	{ -15000, 444 },
17793ab5de6Skettenis 	{ -10000, 453 },
17893ab5de6Skettenis 	{  -5000, 461 },
17993ab5de6Skettenis 	{      0, 470 },
18093ab5de6Skettenis 	{   5000, 478 },
18193ab5de6Skettenis 	{  10000, 487 },
18293ab5de6Skettenis 	{  15000, 496 },
18393ab5de6Skettenis 	{  20000, 504 },
18493ab5de6Skettenis 	{  25000, 513 },
18593ab5de6Skettenis 	{  30000, 521 },
18693ab5de6Skettenis 	{  35000, 530 },
18793ab5de6Skettenis 	{  40000, 538 },
18893ab5de6Skettenis 	{  45000, 547 },
18993ab5de6Skettenis 	{  50000, 555 },
19093ab5de6Skettenis 	{  55000, 564 },
19193ab5de6Skettenis 	{  60000, 573 },
19293ab5de6Skettenis 	{  65000, 581 },
19393ab5de6Skettenis 	{  70000, 590 },
19493ab5de6Skettenis 	{  75000, 599 },
19593ab5de6Skettenis 	{  80000, 607 },
19693ab5de6Skettenis 	{  85000, 616 },
19793ab5de6Skettenis 	{  90000, 624 },
19893ab5de6Skettenis 	{  95000, 633 },
19993ab5de6Skettenis 	{ 100000, 642 },
20093ab5de6Skettenis 	{ 105000, 650 },
20193ab5de6Skettenis 	{ 110000, 659 },
20293ab5de6Skettenis 	{ 115000, 668 },
20393ab5de6Skettenis 	{ 120000, 677 },
2049b6a9f2aSkettenis 	{ 125000, 685 },
20593ab5de6Skettenis };
20693ab5de6Skettenis 
20737c734d3Snaddy const char *const rk3399_names[] = { "CPU", "GPU" };
2089b6a9f2aSkettenis 
2099084a372Skettenis /* RK3568 conversion table. */
2109084a372Skettenis const struct rktemp_entry rk3568_temps[] = {
2119084a372Skettenis 	{ -40000, 1584 },
2129084a372Skettenis 	{ -35000, 1620 },
2139084a372Skettenis 	{ -30000, 1652 },
2149084a372Skettenis 	{ -25000, 1688 },
2159084a372Skettenis 	{ -20000, 1720 },
2169084a372Skettenis 	{ -15000, 1756 },
2179084a372Skettenis 	{ -10000, 1788 },
2189084a372Skettenis 	{  -5000, 1824 },
2199084a372Skettenis 	{      0, 1856 },
2209084a372Skettenis 	{   5000, 1892 },
2219084a372Skettenis 	{  10000, 1924 },
2229084a372Skettenis 	{  15000, 1956 },
2239084a372Skettenis 	{  20000, 1992 },
2249084a372Skettenis 	{  25000, 2024 },
2259084a372Skettenis 	{  30000, 2060 },
2269084a372Skettenis 	{  35000, 2092 },
2279084a372Skettenis 	{  40000, 2128 },
2289084a372Skettenis 	{  45000, 2160 },
2299084a372Skettenis 	{  50000, 2196 },
2309084a372Skettenis 	{  55000, 2228 },
2319084a372Skettenis 	{  60000, 2264 },
2329084a372Skettenis 	{  65000, 2300 },
2339084a372Skettenis 	{  70000, 2332 },
2349084a372Skettenis 	{  75000, 2368 },
2359084a372Skettenis 	{  80000, 2400 },
2369084a372Skettenis 	{  85000, 2436 },
2379084a372Skettenis 	{  90000, 2468 },
2389084a372Skettenis 	{  95000, 2500 },
2399084a372Skettenis 	{ 100000, 2536 },
2409084a372Skettenis 	{ 105000, 2572 },
2419084a372Skettenis 	{ 110000, 2604 },
2429084a372Skettenis 	{ 115000, 2636 },
2439084a372Skettenis 	{ 120000, 2672 },
2449084a372Skettenis 	{ 125000, 2704 },
2459084a372Skettenis };
2469084a372Skettenis 
2479084a372Skettenis const char *const rk3568_names[] = { "CPU", "GPU" };
2489084a372Skettenis 
249f126f9b0Skettenis /* RK3588 conversion table. */
250f126f9b0Skettenis const struct rktemp_entry rk3588_temps[] = {
251f126f9b0Skettenis 	{ -40000, 215 },
252f126f9b0Skettenis 	{  25000, 285 },
253f126f9b0Skettenis 	{  85000, 350 },
254f126f9b0Skettenis 	{ 125000, 395 },
255f126f9b0Skettenis };
256f126f9b0Skettenis 
257f126f9b0Skettenis const char *const rk3588_names[] = {
258f126f9b0Skettenis 	"Top",
259f126f9b0Skettenis 	"CPU (big0)",
260f126f9b0Skettenis 	"CPU (big1)",
261f126f9b0Skettenis 	"CPU (little)",
262f126f9b0Skettenis 	"Center",
263f126f9b0Skettenis 	"GPU",
264f126f9b0Skettenis 	"NPU"
265f126f9b0Skettenis };
266f126f9b0Skettenis 
2679b6a9f2aSkettenis struct rktemp_softc {
2689b6a9f2aSkettenis 	struct device		sc_dev;
2699b6a9f2aSkettenis 	bus_space_tag_t		sc_iot;
2709b6a9f2aSkettenis 	bus_space_handle_t	sc_ioh;
2711d1e9e74Skettenis 	int			sc_node;
272*74b3eef0Skettenis 	void			*sc_ih;
2739b6a9f2aSkettenis 
274f126f9b0Skettenis 	bus_size_t		sc_data0;
275f126f9b0Skettenis 
27637c734d3Snaddy 	const struct rktemp_entry *sc_temps;
2779b6a9f2aSkettenis 	int			sc_ntemps;
2789b6a9f2aSkettenis 
279f126f9b0Skettenis 	struct ksensor		sc_sensors[7];
2809b6a9f2aSkettenis 	int			sc_nsensors;
2819b6a9f2aSkettenis 	struct ksensordev	sc_sensordev;
28238041c6dSkettenis 
28338041c6dSkettenis 	struct thermal_sensor	sc_ts;
2849b6a9f2aSkettenis };
2859b6a9f2aSkettenis 
2869b6a9f2aSkettenis int	rktemp_match(struct device *, void *, void *);
2879b6a9f2aSkettenis void	rktemp_attach(struct device *, struct device *, void *);
2889b6a9f2aSkettenis 
2899fdf0c62Smpi const struct cfattach rktemp_ca = {
2909b6a9f2aSkettenis 	sizeof (struct rktemp_softc), rktemp_match, rktemp_attach
2919b6a9f2aSkettenis };
2929b6a9f2aSkettenis 
2939b6a9f2aSkettenis struct cfdriver rktemp_cd = {
2949b6a9f2aSkettenis 	NULL, "rktemp", DV_DULL
2959b6a9f2aSkettenis };
2969b6a9f2aSkettenis 
297*74b3eef0Skettenis int	rktemp_intr(void *);
2981d1e9e74Skettenis void	rktemp_rk3568_init(struct rktemp_softc *);
2999b6a9f2aSkettenis int32_t rktemp_calc_code(struct rktemp_softc *, int32_t);
3009b6a9f2aSkettenis int32_t rktemp_calc_temp(struct rktemp_softc *, int32_t);
3019b6a9f2aSkettenis int	rktemp_valid(struct rktemp_softc *, int32_t);
3029b6a9f2aSkettenis void	rktemp_refresh_sensors(void *);
30338041c6dSkettenis int32_t	rktemp_get_temperature(void *, uint32_t *);
304*74b3eef0Skettenis int	rktemp_set_limit(void *, uint32_t *, uint32_t);
3059b6a9f2aSkettenis 
3069b6a9f2aSkettenis int
rktemp_match(struct device * parent,void * match,void * aux)3079b6a9f2aSkettenis rktemp_match(struct device *parent, void *match, void *aux)
30893ab5de6Skettenis {
3099b6a9f2aSkettenis 	struct fdt_attach_args *faa = aux;
3109b6a9f2aSkettenis 
3119b6a9f2aSkettenis 	return (OF_is_compatible(faa->fa_node, "rockchip,rk3288-tsadc") ||
3125e6272baSjmatthew 	    OF_is_compatible(faa->fa_node, "rockchip,rk3308-tsadc") ||
313bbd23df1Skettenis 	    OF_is_compatible(faa->fa_node, "rockchip,rk3328-tsadc") ||
3149084a372Skettenis 	    OF_is_compatible(faa->fa_node, "rockchip,rk3399-tsadc") ||
315f126f9b0Skettenis 	    OF_is_compatible(faa->fa_node, "rockchip,rk3568-tsadc") ||
316f126f9b0Skettenis 	    OF_is_compatible(faa->fa_node, "rockchip,rk3588-tsadc"));
3179b6a9f2aSkettenis }
3189b6a9f2aSkettenis 
3199b6a9f2aSkettenis void
rktemp_attach(struct device * parent,struct device * self,void * aux)3209b6a9f2aSkettenis rktemp_attach(struct device *parent, struct device *self, void *aux)
3219b6a9f2aSkettenis {
3229b6a9f2aSkettenis 	struct rktemp_softc *sc = (struct rktemp_softc *)self;
3239b6a9f2aSkettenis 	struct fdt_attach_args *faa = aux;
32437c734d3Snaddy 	const char *const *names;
3259b6a9f2aSkettenis 	uint32_t mode, polarity, temp;
326f126f9b0Skettenis 	uint32_t auto_con, inter_pd_soc;
3271d1e9e74Skettenis 	int auto_period, auto_period_ht;
3289b6a9f2aSkettenis 	int i;
3299b6a9f2aSkettenis 
3309b6a9f2aSkettenis 	if (faa->fa_nreg < 1) {
3319b6a9f2aSkettenis 		printf(": no registers\n");
3329b6a9f2aSkettenis 		return;
3339b6a9f2aSkettenis 	}
3349b6a9f2aSkettenis 
3359b6a9f2aSkettenis 	sc->sc_iot = faa->fa_iot;
3361d1e9e74Skettenis 	sc->sc_node = faa->fa_node;
3371d1e9e74Skettenis 
3389b6a9f2aSkettenis 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
3399b6a9f2aSkettenis 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
3409b6a9f2aSkettenis 		printf(": can't map registers\n");
3419b6a9f2aSkettenis 		return;
3429b6a9f2aSkettenis 	}
3439b6a9f2aSkettenis 
344*74b3eef0Skettenis 	if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-tsadc")) {
345*74b3eef0Skettenis 		sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_SOFTCLOCK,
346*74b3eef0Skettenis 		    rktemp_intr, sc, sc->sc_dev.dv_xname);
347*74b3eef0Skettenis 		if (sc->sc_ih == NULL) {
348*74b3eef0Skettenis 			printf(": can't establish interrupt\n");
349*74b3eef0Skettenis 			return;
350*74b3eef0Skettenis 		}
351*74b3eef0Skettenis 	}
352*74b3eef0Skettenis 
3539b6a9f2aSkettenis 	printf("\n");
3549b6a9f2aSkettenis 
3551d1e9e74Skettenis 	if (OF_is_compatible(sc->sc_node, "rockchip,rk3288-tsadc")) {
3569b6a9f2aSkettenis 		sc->sc_temps = rk3288_temps;
3579b6a9f2aSkettenis 		sc->sc_ntemps = nitems(rk3288_temps);
3589b6a9f2aSkettenis 		sc->sc_nsensors = 3;
3599b6a9f2aSkettenis 		names = rk3288_names;
3601d1e9e74Skettenis 		inter_pd_soc = 13;
3611d1e9e74Skettenis 		auto_period = 250;	/* 250 ms */
3621d1e9e74Skettenis 		auto_period_ht = 50;	/* 50 ms */
3631d1e9e74Skettenis 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3308-tsadc")) {
3645e6272baSjmatthew 		sc->sc_temps = rk3328_temps;
3655e6272baSjmatthew 		sc->sc_ntemps = nitems(rk3328_temps);
3665e6272baSjmatthew 		sc->sc_nsensors = 2;
3675e6272baSjmatthew 		names = rk3308_names;
3681d1e9e74Skettenis 		inter_pd_soc = 13;
3691d1e9e74Skettenis 		auto_period = 1875;	/* 2.5 ms */
3701d1e9e74Skettenis 		auto_period_ht = 1875;	/* 2.5 ms */
3711d1e9e74Skettenis 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3328-tsadc")) {
372bbd23df1Skettenis 		sc->sc_temps = rk3328_temps;
373bbd23df1Skettenis 		sc->sc_ntemps = nitems(rk3328_temps);
374bbd23df1Skettenis 		sc->sc_nsensors = 1;
375bbd23df1Skettenis 		names = rk3328_names;
3761d1e9e74Skettenis 		inter_pd_soc = 13;
3771d1e9e74Skettenis 		auto_period = 1875;	/* 2.5 ms */
3781d1e9e74Skettenis 		auto_period_ht = 1875;	/* 2.5 ms */
3791d1e9e74Skettenis 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3399-tsadc")) {
3809b6a9f2aSkettenis 		sc->sc_temps = rk3399_temps;
3819b6a9f2aSkettenis 		sc->sc_ntemps = nitems(rk3399_temps);
3829b6a9f2aSkettenis 		sc->sc_nsensors = 2;
3839b6a9f2aSkettenis 		names = rk3399_names;
3841d1e9e74Skettenis 		inter_pd_soc = 13;
3851d1e9e74Skettenis 		auto_period = 1875;	/* 2.5 ms */
3861d1e9e74Skettenis 		auto_period_ht = 1875;	/* 2.5 ms */
387f126f9b0Skettenis 	} else if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-tsadc")) {
3889084a372Skettenis 		sc->sc_temps = rk3568_temps;
3899084a372Skettenis 		sc->sc_ntemps = nitems(rk3568_temps);
3909084a372Skettenis 		sc->sc_nsensors = 2;
3919084a372Skettenis 		names = rk3568_names;
3921d1e9e74Skettenis 		inter_pd_soc = 63;	/* 97 us */
3931d1e9e74Skettenis 		auto_period = 1622;	/* 2.5 ms */
3941d1e9e74Skettenis 		auto_period_ht = 1622;	/* 2.5 ms */
395f126f9b0Skettenis 	} else {
396f126f9b0Skettenis 		sc->sc_temps = rk3588_temps;
397f126f9b0Skettenis 		sc->sc_ntemps = nitems(rk3588_temps);
398f126f9b0Skettenis 		sc->sc_nsensors = 7;
399f126f9b0Skettenis 		names = rk3588_names;
400f126f9b0Skettenis 		inter_pd_soc = 0;
401f126f9b0Skettenis 		auto_period = 5000;	/* 2.5 ms */
402f126f9b0Skettenis 		auto_period_ht = 5000;	/* 2.5 ms */
4039b6a9f2aSkettenis 	}
4049b6a9f2aSkettenis 
4051d1e9e74Skettenis 	pinctrl_byname(sc->sc_node, "init");
4069b6a9f2aSkettenis 
4071d1e9e74Skettenis 	clock_set_assigned(sc->sc_node);
4081d1e9e74Skettenis 	clock_enable(sc->sc_node, "tsadc");
4091d1e9e74Skettenis 	clock_enable(sc->sc_node, "apb_pclk");
4109b6a9f2aSkettenis 
4119b6a9f2aSkettenis 	/* Reset the TS-ADC controller block. */
412f126f9b0Skettenis 	reset_assert_all(sc->sc_node);
4139b6a9f2aSkettenis 	delay(10);
414f126f9b0Skettenis 	reset_deassert_all(sc->sc_node);
4159b6a9f2aSkettenis 
4161d1e9e74Skettenis 	mode = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-mode", 1);
4171d1e9e74Skettenis 	polarity = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-polarity", 0);
4181d1e9e74Skettenis 	temp = OF_getpropint(sc->sc_node, "rockchip,hw-tshut-temp", 95000);
4191d1e9e74Skettenis 
420f126f9b0Skettenis 	if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-tsadc")) {
421f126f9b0Skettenis 		uint32_t gpio_en, cru_en;
422f126f9b0Skettenis 
423f126f9b0Skettenis 		sc->sc_data0 = TSADC_V3_DATA(0);
424f126f9b0Skettenis 
425f126f9b0Skettenis 		HWRITE4(sc, TSADC_V3_AUTO_PERIOD, auto_period);
426f126f9b0Skettenis 		HWRITE4(sc, TSADC_V3_AUTO_PERIOD_HT, auto_period_ht);
427f126f9b0Skettenis 		HWRITE4(sc, TSADC_V3_HIGHT_INT_DEBOUNCE, 4);
428f126f9b0Skettenis 		HWRITE4(sc, TSADC_V3_HIGHT_TSHUT_DEBOUNCE, 4);
429f126f9b0Skettenis 
430f126f9b0Skettenis 		auto_con = TSADC_AUTO_CON_TSHUT_POLARITY << 16;
431f126f9b0Skettenis 		if (polarity)
432f126f9b0Skettenis 			auto_con = TSADC_AUTO_CON_TSHUT_POLARITY;
433f126f9b0Skettenis 		HWRITE4(sc, TSADC_AUTO_CON, auto_con);
434f126f9b0Skettenis 
435f126f9b0Skettenis 		/* Set shutdown limit. */
436f126f9b0Skettenis 		for (i = 0; i < sc->sc_nsensors; i++) {
437f126f9b0Skettenis 			HWRITE4(sc, TSADC_V3_COMP_SHUT(i),
438f126f9b0Skettenis 			    rktemp_calc_code(sc, temp));
439f126f9b0Skettenis 			HWRITE4(sc, TSADC_V3_AUTO_SRC,
440f126f9b0Skettenis 			    TSADC_V3_AUTO_SRC_CH(i) << 16 |
441f126f9b0Skettenis 			    TSADC_V3_AUTO_SRC_CH(i));
442f126f9b0Skettenis 		}
443f126f9b0Skettenis 
444f126f9b0Skettenis 		/* Clear shutdown output status. */
445f126f9b0Skettenis 		for (i = 0; i < sc->sc_nsensors; i++) {
446f126f9b0Skettenis 			HWRITE4(sc, TSADC_V3_HLT_INT_PD,
447f126f9b0Skettenis 			    TSADC_V3_HT_INT_STATUS(i));
448f126f9b0Skettenis 		}
449f126f9b0Skettenis 
450f126f9b0Skettenis 		/* Configure mode. */
451f126f9b0Skettenis 		gpio_en = cru_en = 0;
452f126f9b0Skettenis 		for (i = 0; i < sc->sc_nsensors; i++) {
453f126f9b0Skettenis 			gpio_en |= TSADC_V3_GPIO_EN_CH(i) << 16;
454f126f9b0Skettenis 			cru_en |= TSADC_V3_CRU_EN_CH(i) << 16;
455f126f9b0Skettenis 			if (mode)
456f126f9b0Skettenis 				gpio_en |= TSADC_V3_GPIO_EN_CH(i);
457f126f9b0Skettenis 			else
458f126f9b0Skettenis 				cru_en |= TSADC_V3_CRU_EN_CH(i);
459f126f9b0Skettenis 		}
460f126f9b0Skettenis 		HWRITE4(sc, TSADC_V3_GPIO_EN, gpio_en);
461f126f9b0Skettenis 		HWRITE4(sc, TSADC_V3_CRU_EN, cru_en);
462f126f9b0Skettenis 	} else {
463f126f9b0Skettenis 		uint32_t int_en;
464f126f9b0Skettenis 
465f126f9b0Skettenis 		sc->sc_data0 = TSADC_DATA(0);
466f126f9b0Skettenis 
4671d1e9e74Skettenis 		HWRITE4(sc, TSADC_USER_CON,
4681d1e9e74Skettenis 		    inter_pd_soc << TSADC_USER_CON_INTER_PD_SOC_SHIFT);
4691d1e9e74Skettenis 		HWRITE4(sc, TSADC_AUTO_PERIOD, auto_period);
4701d1e9e74Skettenis 		HWRITE4(sc, TSADC_AUTO_PERIOD_HT, auto_period_ht);
4711d1e9e74Skettenis 		HWRITE4(sc, TSADC_HIGHT_INT_DEBOUNCE, 4);
4721d1e9e74Skettenis 		HWRITE4(sc, TSADC_HIGHT_TSHUT_DEBOUNCE, 4);
4731d1e9e74Skettenis 
4741d1e9e74Skettenis 		if (OF_is_compatible(sc->sc_node, "rockchip,rk3568-tsadc"))
4751d1e9e74Skettenis 			rktemp_rk3568_init(sc);
4769b6a9f2aSkettenis 
4779b6a9f2aSkettenis 		auto_con = HREAD4(sc, TSADC_AUTO_CON);
4789b6a9f2aSkettenis 		auto_con |= TSADC_AUTO_CON_TSADC_Q_SEL;
4799b6a9f2aSkettenis 		if (polarity)
4809b6a9f2aSkettenis 			auto_con |= TSADC_AUTO_CON_TSHUT_POLARITY;
4819b6a9f2aSkettenis 		HWRITE4(sc, TSADC_AUTO_CON, auto_con);
4829b6a9f2aSkettenis 
4839084a372Skettenis 		/* Set shutdown limit. */
4849084a372Skettenis 		for (i = 0; i < sc->sc_nsensors; i++) {
485f126f9b0Skettenis 			HWRITE4(sc, TSADC_COMP_SHUT(i),
4869084a372Skettenis 			    rktemp_calc_code(sc, temp));
487f126f9b0Skettenis 			auto_con |= (TSADC_AUTO_CON_SRC_EN(i));
4889084a372Skettenis 		}
4899084a372Skettenis 		HWRITE4(sc, TSADC_AUTO_CON, auto_con);
4909084a372Skettenis 
4919084a372Skettenis 		/* Clear shutdown output status. */
4929084a372Skettenis 		for (i = 0; i < sc->sc_nsensors; i++)
493f126f9b0Skettenis 			HWRITE4(sc, TSADC_INT_PD, TSADC_INT_PD_TSHUT_O_SRC(i));
4949084a372Skettenis 
4959b6a9f2aSkettenis 		/* Configure mode. */
4969b6a9f2aSkettenis 		int_en = HREAD4(sc, TSADC_INT_EN);
4979b6a9f2aSkettenis 		for (i = 0; i < sc->sc_nsensors; i++) {
4989b6a9f2aSkettenis 			if (mode)
499f126f9b0Skettenis 				int_en |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC(i);
5009b6a9f2aSkettenis 			else
501f126f9b0Skettenis 				int_en |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC(i);
5029b6a9f2aSkettenis 		}
5039b6a9f2aSkettenis 		HWRITE4(sc, TSADC_INT_EN, int_en);
504f126f9b0Skettenis 	}
5059b6a9f2aSkettenis 
5061d1e9e74Skettenis 	pinctrl_byname(sc->sc_node, "default");
5079b6a9f2aSkettenis 
5089b6a9f2aSkettenis 	/* Finally turn on the ADC. */
509f126f9b0Skettenis 	if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-tsadc")) {
510f126f9b0Skettenis 		HWRITE4(sc, TSADC_AUTO_CON,
511f126f9b0Skettenis 		    TSADC_AUTO_CON_AUTO_EN << 16 | TSADC_AUTO_CON_AUTO_EN);
512f126f9b0Skettenis 	} else {
5139b6a9f2aSkettenis 		auto_con |= TSADC_AUTO_CON_AUTO_EN;
5149b6a9f2aSkettenis 		HWRITE4(sc, TSADC_AUTO_CON, auto_con);
515f126f9b0Skettenis 	}
5169b6a9f2aSkettenis 
5179b6a9f2aSkettenis 	/* Register sensors. */
5189b6a9f2aSkettenis 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
5199b6a9f2aSkettenis 	    sizeof(sc->sc_sensordev.xname));
5209b6a9f2aSkettenis 	for (i = 0; i < sc->sc_nsensors; i++) {
5219b6a9f2aSkettenis 		strlcpy(sc->sc_sensors[i].desc, names[i],
5229b6a9f2aSkettenis 		    sizeof(sc->sc_sensors[i].desc));
5239b6a9f2aSkettenis 		sc->sc_sensors[i].type = SENSOR_TEMP;
5249b6a9f2aSkettenis 		sc->sc_sensors[i].flags = SENSOR_FINVALID;
5259b6a9f2aSkettenis 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
5269b6a9f2aSkettenis 	}
5279b6a9f2aSkettenis 	sensordev_install(&sc->sc_sensordev);
5289b6a9f2aSkettenis 	sensor_task_register(sc, rktemp_refresh_sensors, 5);
52938041c6dSkettenis 
5301d1e9e74Skettenis 	sc->sc_ts.ts_node = sc->sc_node;
53138041c6dSkettenis 	sc->sc_ts.ts_cookie = sc;
53238041c6dSkettenis 	sc->sc_ts.ts_get_temperature = rktemp_get_temperature;
533*74b3eef0Skettenis 	if (OF_is_compatible(sc->sc_node, "rockchip,rk3588-tsadc"))
534*74b3eef0Skettenis 		sc->sc_ts.ts_set_limit = rktemp_set_limit;
53538041c6dSkettenis 	thermal_sensor_register(&sc->sc_ts);
5369b6a9f2aSkettenis }
5379b6a9f2aSkettenis 
538*74b3eef0Skettenis int
rktemp_intr(void * arg)539*74b3eef0Skettenis rktemp_intr(void *arg)
540*74b3eef0Skettenis {
541*74b3eef0Skettenis 	struct rktemp_softc *sc = arg;
542*74b3eef0Skettenis 	uint32_t stat, ch;
543*74b3eef0Skettenis 
544*74b3eef0Skettenis 	stat = HREAD4(sc, TSADC_V3_HLT_INT_PD);
545*74b3eef0Skettenis 	stat &= HREAD4(sc, TSADC_V3_HT_INT_EN);
546*74b3eef0Skettenis 	for (ch = 0; ch < sc->sc_nsensors; ch++) {
547*74b3eef0Skettenis 		if (stat & TSADC_V3_HT_INT_STATUS(ch))
548*74b3eef0Skettenis 			thermal_sensor_update(&sc->sc_ts, &ch);
549*74b3eef0Skettenis 	}
550*74b3eef0Skettenis 
551*74b3eef0Skettenis 	/*
552*74b3eef0Skettenis 	 * Disable and clear the active interrupts.  The thermal zone
553*74b3eef0Skettenis 	 * code will set a new limit when necessary.
554*74b3eef0Skettenis 	 */
555*74b3eef0Skettenis 	HWRITE4(sc, TSADC_V3_HT_INT_EN, stat << 16);
556*74b3eef0Skettenis 	HWRITE4(sc, TSADC_V3_HLT_INT_PD, stat);
557*74b3eef0Skettenis 
558*74b3eef0Skettenis 	return 1;
559*74b3eef0Skettenis }
560*74b3eef0Skettenis 
5611d1e9e74Skettenis void
rktemp_rk3568_init(struct rktemp_softc * sc)5621d1e9e74Skettenis rktemp_rk3568_init(struct rktemp_softc *sc)
5631d1e9e74Skettenis {
5641d1e9e74Skettenis 	struct regmap *rm;
5651d1e9e74Skettenis 	uint32_t grf;
5661d1e9e74Skettenis 	int i;
5671d1e9e74Skettenis 
5681d1e9e74Skettenis 	grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0);
5691d1e9e74Skettenis 	rm = regmap_byphandle(grf);
5701d1e9e74Skettenis 	if (rm == 0)
5711d1e9e74Skettenis 		return;
5721d1e9e74Skettenis 
5731d1e9e74Skettenis 	regmap_write_4(rm, RK3568_GRF_TSADC_CON,
5741d1e9e74Skettenis 	    RK3568_GRF_TSADC_EN << 16 | RK3568_GRF_TSADC_EN);
5751d1e9e74Skettenis 	delay(15);
5761d1e9e74Skettenis 	for (i = 0; i <= 2; i++) {
5771d1e9e74Skettenis 		regmap_write_4(rm, RK3568_GRF_TSADC_CON,
5781d1e9e74Skettenis 		    RK3568_GRF_TSADC_ANA_REG(i) << 16 |
5791d1e9e74Skettenis 		    RK3568_GRF_TSADC_ANA_REG(i));
5801d1e9e74Skettenis 	}
5811d1e9e74Skettenis 	delay(100);
5821d1e9e74Skettenis }
5831d1e9e74Skettenis 
5849b6a9f2aSkettenis int32_t
rktemp_calc_code(struct rktemp_softc * sc,int32_t temp)5859b6a9f2aSkettenis rktemp_calc_code(struct rktemp_softc *sc, int32_t temp)
5869b6a9f2aSkettenis {
5879b6a9f2aSkettenis 	const int n = sc->sc_ntemps;
5889b6a9f2aSkettenis 	int32_t code0, delta_code;
58993ab5de6Skettenis 	int32_t temp0, delta_temp;
59093ab5de6Skettenis 	int i;
59193ab5de6Skettenis 
5929b6a9f2aSkettenis 	if (temp <= sc->sc_temps[0].temp)
5939b6a9f2aSkettenis 		return sc->sc_temps[0].code;
5949b6a9f2aSkettenis 	if (temp >= sc->sc_temps[n - 1].temp)
5959b6a9f2aSkettenis 		return sc->sc_temps[n - 1].code;
59693ab5de6Skettenis 
59793ab5de6Skettenis 	for (i = 1; i < n; i++) {
5989b6a9f2aSkettenis 		if (temp < sc->sc_temps[i].temp)
59993ab5de6Skettenis 			break;
60093ab5de6Skettenis 	}
60193ab5de6Skettenis 
6029b6a9f2aSkettenis 	code0 = sc->sc_temps[i - 1].code;
6039b6a9f2aSkettenis 	temp0 = sc->sc_temps[i - 1].temp;
6049b6a9f2aSkettenis 	delta_code = sc->sc_temps[i].code - code0;
6059b6a9f2aSkettenis 	delta_temp = sc->sc_temps[i].temp - temp0;
60693ab5de6Skettenis 
60793ab5de6Skettenis 	return code0 + (temp - temp0) * delta_code / delta_temp;
60893ab5de6Skettenis }
60993ab5de6Skettenis 
61093ab5de6Skettenis int32_t
rktemp_calc_temp(struct rktemp_softc * sc,int32_t code)6119b6a9f2aSkettenis rktemp_calc_temp(struct rktemp_softc *sc, int32_t code)
61293ab5de6Skettenis {
6139b6a9f2aSkettenis 	const int n = sc->sc_ntemps;
6149b6a9f2aSkettenis 	int32_t code0, delta_code;
61593ab5de6Skettenis 	int32_t temp0, delta_temp;
61693ab5de6Skettenis 	int i;
61793ab5de6Skettenis 
6184b1a56afSjsg 	/* Handle both negative and positive temperature coefficients. */
6199b6a9f2aSkettenis 	if (sc->sc_temps[0].code > sc->sc_temps[1].code) {
6209b6a9f2aSkettenis 		if (code >= sc->sc_temps[0].code)
6219b6a9f2aSkettenis 			return sc->sc_temps[0].code;
6229b6a9f2aSkettenis 		if (code <= sc->sc_temps[n - 1].code)
6239b6a9f2aSkettenis 			return sc->sc_temps[n - 1].temp;
62493ab5de6Skettenis 
62593ab5de6Skettenis 		for (i = 1; i < n; i++) {
6269b6a9f2aSkettenis 			if (code > sc->sc_temps[i].code)
62793ab5de6Skettenis 				break;
62893ab5de6Skettenis 		}
6299b6a9f2aSkettenis 	} else {
6309b6a9f2aSkettenis 		if (code <= sc->sc_temps[0].code)
6319b6a9f2aSkettenis 			return sc->sc_temps[0].temp;
6329b6a9f2aSkettenis 		if (code >= sc->sc_temps[n - 1].code)
6339b6a9f2aSkettenis 			return sc->sc_temps[n - 1].temp;
63493ab5de6Skettenis 
6359b6a9f2aSkettenis 		for (i = 1; i < n; i++) {
6369b6a9f2aSkettenis 			if (code < sc->sc_temps[i].code)
6379b6a9f2aSkettenis 				break;
6389b6a9f2aSkettenis 		}
6399b6a9f2aSkettenis 	}
6409b6a9f2aSkettenis 
6419b6a9f2aSkettenis 	code0 = sc->sc_temps[i - 1].code;
6429b6a9f2aSkettenis 	temp0 = sc->sc_temps[i - 1].temp;
6439b6a9f2aSkettenis 	delta_code = sc->sc_temps[i].code - code0;
6449b6a9f2aSkettenis 	delta_temp = sc->sc_temps[i].temp - temp0;
64593ab5de6Skettenis 
64693ab5de6Skettenis 	return temp0 + (code - code0) * delta_temp / delta_code;
64793ab5de6Skettenis }
64893ab5de6Skettenis 
64993ab5de6Skettenis int
rktemp_valid(struct rktemp_softc * sc,int32_t code)6509b6a9f2aSkettenis rktemp_valid(struct rktemp_softc *sc, int32_t code)
65193ab5de6Skettenis {
6529b6a9f2aSkettenis 	const int n = sc->sc_ntemps;
65393ab5de6Skettenis 
6549b6a9f2aSkettenis 	if (sc->sc_temps[0].code > sc->sc_temps[1].code) {
6559b6a9f2aSkettenis 		if (code > sc->sc_temps[0].code)
65693ab5de6Skettenis 			return 0;
6579b6a9f2aSkettenis 		if (code < sc->sc_temps[n - 1].code)
65893ab5de6Skettenis 			return 0;
6599b6a9f2aSkettenis 	} else {
6609b6a9f2aSkettenis 		if (code < sc->sc_temps[0].code)
6619b6a9f2aSkettenis 			return 0;
6629b6a9f2aSkettenis 		if (code > sc->sc_temps[n - 1].code)
6639b6a9f2aSkettenis 			return 0;
6649b6a9f2aSkettenis 	}
66593ab5de6Skettenis 	return 1;
66693ab5de6Skettenis }
66793ab5de6Skettenis 
66893ab5de6Skettenis void
rktemp_refresh_sensors(void * arg)66993ab5de6Skettenis rktemp_refresh_sensors(void *arg)
67093ab5de6Skettenis {
67193ab5de6Skettenis 	struct rktemp_softc *sc = arg;
6729b6a9f2aSkettenis 	int32_t code, temp;
6739b6a9f2aSkettenis 	int i;
67493ab5de6Skettenis 
6759b6a9f2aSkettenis 	for (i = 0; i < sc->sc_nsensors; i++) {
676f126f9b0Skettenis 		code = HREAD4(sc, sc->sc_data0 + (i * 4));
6779b6a9f2aSkettenis 		temp = rktemp_calc_temp(sc, code);
6789b6a9f2aSkettenis 		sc->sc_sensors[i].value = 273150000 + 1000 * temp;
6799b6a9f2aSkettenis 		if (rktemp_valid(sc, code))
6809b6a9f2aSkettenis 			sc->sc_sensors[i].flags &= ~SENSOR_FINVALID;
68193ab5de6Skettenis 		else
6829b6a9f2aSkettenis 			sc->sc_sensors[i].flags |= SENSOR_FINVALID;
6839b6a9f2aSkettenis 	}
68493ab5de6Skettenis }
68538041c6dSkettenis 
68638041c6dSkettenis int32_t
rktemp_get_temperature(void * cookie,uint32_t * cells)68738041c6dSkettenis rktemp_get_temperature(void *cookie, uint32_t *cells)
68838041c6dSkettenis {
68938041c6dSkettenis 	struct rktemp_softc *sc = cookie;
690*74b3eef0Skettenis 	uint32_t ch = cells[0];
69138041c6dSkettenis 	int32_t code;
69238041c6dSkettenis 
693*74b3eef0Skettenis 	if (ch >= sc->sc_nsensors)
69438041c6dSkettenis 		return THERMAL_SENSOR_MAX;
69538041c6dSkettenis 
696*74b3eef0Skettenis 	code = HREAD4(sc, sc->sc_data0 + (ch * 4));
69738041c6dSkettenis 	if (rktemp_valid(sc, code))
69838041c6dSkettenis 		return rktemp_calc_temp(sc, code);
69938041c6dSkettenis 	else
70038041c6dSkettenis 		return THERMAL_SENSOR_MAX;
70138041c6dSkettenis }
702*74b3eef0Skettenis 
703*74b3eef0Skettenis int
rktemp_set_limit(void * cookie,uint32_t * cells,uint32_t temp)704*74b3eef0Skettenis rktemp_set_limit(void *cookie, uint32_t *cells, uint32_t temp)
705*74b3eef0Skettenis {
706*74b3eef0Skettenis 	struct rktemp_softc *sc = cookie;
707*74b3eef0Skettenis 	uint32_t ch = cells[0];
708*74b3eef0Skettenis 
709*74b3eef0Skettenis 	if (ch >= sc->sc_nsensors)
710*74b3eef0Skettenis 		return ENXIO;
711*74b3eef0Skettenis 
712*74b3eef0Skettenis 	/* Set limit for this sensor. */
713*74b3eef0Skettenis 	HWRITE4(sc, TSADC_V3_COMP_INT(ch), rktemp_calc_code(sc, temp));
714*74b3eef0Skettenis 
715*74b3eef0Skettenis 	/* Clear and enable the corresponding interrupt. */
716*74b3eef0Skettenis 	HWRITE4(sc, TSADC_V3_HLT_INT_PD, TSADC_V3_HT_INT_STATUS(ch));
717*74b3eef0Skettenis 	HWRITE4(sc, TSADC_V3_HT_INT_EN, TSADC_V3_HT_INT_EN_CH(ch) << 16 |
718*74b3eef0Skettenis 	    TSADC_V3_HT_INT_EN_CH(ch));
719*74b3eef0Skettenis 
720*74b3eef0Skettenis 	return 0;
721*74b3eef0Skettenis }
722