xref: /openbsd-src/sys/dev/fdt/rktemp.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$OpenBSD: rktemp.c,v 1.2 2017/12/29 10:39:01 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/fdt.h>
32 
33 /* Registers */
34 #define TSADC_USER_CON		0x0000
35 #define TSADC_AUTO_CON		0x0004
36 #define  TSADC_AUTO_CON_TSHUT_POLARITY	(1 << 8)
37 #define  TSADC_AUTO_CON_SRC3_EN		(1 << 7)
38 #define  TSADC_AUTO_CON_SRC2_EN		(1 << 6)
39 #define  TSADC_AUTO_CON_SRC1_EN		(1 << 5)
40 #define  TSADC_AUTO_CON_SRC0_EN		(1 << 4)
41 #define  TSADC_AUTO_CON_TSADC_Q_SEL	(1 << 1)
42 #define  TSADC_AUTO_CON_AUTO_EN		(1 << 0)
43 #define TSADC_INT_EN		0x0008
44 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC3	(1 << 11)
45 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC2	(1 << 10)
46 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC1	(1 << 9)
47 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC0	(1 << 8)
48 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC3	(1 << 7)
49 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC2	(1 << 6)
50 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1	(1 << 5)
51 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0	(1 << 4)
52 #define TSADC_INT_PD		0x000c
53 #define TSADC_DATA0		0x0020
54 #define TSADC_DATA1		0x0024
55 #define TSADC_DATA2		0x0028
56 #define TSADC_DATA3		0x002c
57 #define TSADC_COMP0_INT		0x0030
58 #define TSADC_COMP1_INT		0x0034
59 #define TSADC_COMP2_INT		0x0038
60 #define TSADC_COMP3_INT		0x003c
61 #define TSADC_COMP0_SHUT	0x0040
62 #define TSADC_COMP1_SHUT	0x0044
63 #define TSADC_COMP2_SHUT	0x0048
64 #define TSADC_COMP3_SHUT	0x004c
65 #define TSADC_AUTO_PERIOD	0x0068
66 #define TSADC_AUTO_PERIOD_HT	0x006c
67 
68 #define HREAD4(sc, reg)							\
69 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
70 #define HWRITE4(sc, reg, val)						\
71 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
72 
73 struct rktemp_entry {
74 	int32_t temp;
75 	int32_t code;
76 };
77 
78 /* RK3288 conversion table. */
79 struct rktemp_entry rk3288_temps[] = {
80 	{ -40000, 3800 },
81 	{ -35000, 3792 },
82 	{ -30000, 3783 },
83 	{ -25000, 3774 },
84 	{ -20000, 3765 },
85 	{ -15000, 3756 },
86 	{ -10000, 3747 },
87 	{  -5000, 3737 },
88 	{      0, 3728 },
89 	{   5000, 3718 },
90 	{  10000, 3708 },
91 	{  15000, 3698 },
92 	{  20000, 3688 },
93 	{  25000, 3678 },
94 	{  30000, 3667 },
95 	{  35000, 3656 },
96 	{  40000, 3645 },
97 	{  45000, 3634 },
98 	{  50000, 3623 },
99 	{  55000, 3611 },
100 	{  60000, 3600 },
101 	{  65000, 3588 },
102 	{  70000, 3575 },
103 	{  75000, 3563 },
104 	{  80000, 3550 },
105 	{  85000, 3537 },
106 	{  90000, 3524 },
107 	{  95000, 3510 },
108 	{ 100000, 3496 },
109 	{ 105000, 3482 },
110 	{ 110000, 3467 },
111 	{ 115000, 3452 },
112 	{ 120000, 3437 },
113 	{ 125000, 3421 },
114 };
115 
116 const char *rk3288_names[] = { "", "CPU", "GPU" };
117 
118 /* RK3399 conversion table. */
119 struct rktemp_entry rk3399_temps[] = {
120 	{ -40000, 402 },
121 	{ -35000, 410 },
122 	{ -30000, 419 },
123 	{ -25000, 427 },
124 	{ -20000, 436 },
125 	{ -15000, 444 },
126 	{ -10000, 453 },
127 	{  -5000, 461 },
128 	{      0, 470 },
129 	{   5000, 478 },
130 	{  10000, 487 },
131 	{  15000, 496 },
132 	{  20000, 504 },
133 	{  25000, 513 },
134 	{  30000, 521 },
135 	{  35000, 530 },
136 	{  40000, 538 },
137 	{  45000, 547 },
138 	{  50000, 555 },
139 	{  55000, 564 },
140 	{  60000, 573 },
141 	{  65000, 581 },
142 	{  70000, 590 },
143 	{  75000, 599 },
144 	{  80000, 607 },
145 	{  85000, 616 },
146 	{  90000, 624 },
147 	{  95000, 633 },
148 	{ 100000, 642 },
149 	{ 105000, 650 },
150 	{ 110000, 659 },
151 	{ 115000, 668 },
152 	{ 120000, 677 },
153 	{ 125000, 685 },
154 };
155 
156 const char *rk3399_names[] = { "CPU", "GPU" };
157 
158 struct rktemp_softc {
159 	struct device		sc_dev;
160 	bus_space_tag_t		sc_iot;
161 	bus_space_handle_t	sc_ioh;
162 
163 	struct rktemp_entry	*sc_temps;
164 	int			sc_ntemps;
165 
166 	struct ksensor		sc_sensors[3];
167 	int			sc_nsensors;
168 	struct ksensordev	sc_sensordev;
169 };
170 
171 int	rktemp_match(struct device *, void *, void *);
172 void	rktemp_attach(struct device *, struct device *, void *);
173 
174 struct cfattach	rktemp_ca = {
175 	sizeof (struct rktemp_softc), rktemp_match, rktemp_attach
176 };
177 
178 struct cfdriver rktemp_cd = {
179 	NULL, "rktemp", DV_DULL
180 };
181 
182 int32_t rktemp_calc_code(struct rktemp_softc *, int32_t);
183 int32_t rktemp_calc_temp(struct rktemp_softc *, int32_t);
184 int	rktemp_valid(struct rktemp_softc *, int32_t);
185 void	rktemp_refresh_sensors(void *);
186 
187 int
188 rktemp_match(struct device *parent, void *match, void *aux)
189 {
190 	struct fdt_attach_args *faa = aux;
191 
192 	return (OF_is_compatible(faa->fa_node, "rockchip,rk3288-tsadc") ||
193 	    OF_is_compatible(faa->fa_node, "rockchip,rk3399-tsadc"));
194 }
195 
196 void
197 rktemp_attach(struct device *parent, struct device *self, void *aux)
198 {
199 	struct rktemp_softc *sc = (struct rktemp_softc *)self;
200 	struct fdt_attach_args *faa = aux;
201 	const char **names;
202 	uint32_t mode, polarity, temp;
203 	uint32_t auto_con, int_en;
204 	int node = faa->fa_node;
205 	int i;
206 
207 	if (faa->fa_nreg < 1) {
208 		printf(": no registers\n");
209 		return;
210 	}
211 
212 	sc->sc_iot = faa->fa_iot;
213 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
214 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
215 		printf(": can't map registers\n");
216 		return;
217 	}
218 
219 	printf("\n");
220 
221 	if (OF_is_compatible(node, "rockchip,rk3288-tsadc")) {
222 		sc->sc_temps = rk3288_temps;
223 		sc->sc_ntemps = nitems(rk3288_temps);
224 		sc->sc_nsensors = 3;
225 		names = rk3288_names;
226 	} else {
227 		sc->sc_temps = rk3399_temps;
228 		sc->sc_ntemps = nitems(rk3399_temps);
229 		sc->sc_nsensors = 2;
230 		names = rk3399_names;
231 	}
232 
233 	pinctrl_byname(node, "init");
234 
235 	clock_enable(node, "tsadc");
236 	clock_enable(node, "apb_pclk");
237 
238 	/* Reset the TS-ADC controller block. */
239 	reset_assert(node, "tsadc-apb");
240 	delay(10);
241 	reset_deassert(node, "tsadc-apb");
242 
243 	mode = OF_getpropint(node, "rockchip,hw-tshut-mode", 1);
244 	polarity = OF_getpropint(node, "rockchip,hw-tshut-polarity", 0);
245 	temp = OF_getpropint(node, "rockchip,hw-tshut-temp", 95000);
246 
247 	auto_con = HREAD4(sc, TSADC_AUTO_CON);
248 	auto_con |= TSADC_AUTO_CON_TSADC_Q_SEL;
249 	if (polarity)
250 		auto_con |= TSADC_AUTO_CON_TSHUT_POLARITY;
251 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
252 
253 	/* Configure mode. */
254 	int_en = HREAD4(sc, TSADC_INT_EN);
255 	for (i = 0; i < sc->sc_nsensors; i++) {
256 		if (mode)
257 			int_en |= (TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0 << i);
258 		else
259 			int_en |= (TSADC_INT_EN_TSHUT_2CRU_EN_SRC0 << i);
260 	}
261 	HWRITE4(sc, TSADC_INT_EN, int_en);
262 
263 	/* Set shutdown limit. */
264 	for (i = 0; i < sc->sc_nsensors; i++) {
265 		HWRITE4(sc, TSADC_COMP0_SHUT + i * 4,
266 		    rktemp_calc_code(sc, temp));
267 		auto_con |= (TSADC_AUTO_CON_SRC0_EN << i);
268 	}
269 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
270 
271 	pinctrl_byname(faa->fa_node, "default");
272 
273 	/* Finally turn on the ADC. */
274 	auto_con |= TSADC_AUTO_CON_AUTO_EN;
275 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
276 
277 	/* Register sensors. */
278 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
279 	    sizeof(sc->sc_sensordev.xname));
280 	for (i = 0; i < sc->sc_nsensors; i++) {
281 		strlcpy(sc->sc_sensors[i].desc, names[i],
282 		    sizeof(sc->sc_sensors[i].desc));
283 		sc->sc_sensors[i].type = SENSOR_TEMP;
284 		sc->sc_sensors[i].flags = SENSOR_FINVALID;
285 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
286 	}
287 	sensordev_install(&sc->sc_sensordev);
288 	sensor_task_register(sc, rktemp_refresh_sensors, 5);
289 }
290 
291 int32_t
292 rktemp_calc_code(struct rktemp_softc *sc, int32_t temp)
293 {
294 	const int n = sc->sc_ntemps;
295 	int32_t code0, delta_code;
296 	int32_t temp0, delta_temp;
297 	int i;
298 
299 	if (temp <= sc->sc_temps[0].temp)
300 		return sc->sc_temps[0].code;
301 	if (temp >= sc->sc_temps[n - 1].temp)
302 		return sc->sc_temps[n - 1].code;
303 
304 	for (i = 1; i < n; i++) {
305 		if (temp < sc->sc_temps[i].temp)
306 			break;
307 	}
308 
309 	code0 = sc->sc_temps[i - 1].code;
310 	temp0 = sc->sc_temps[i - 1].temp;
311 	delta_code = sc->sc_temps[i].code - code0;
312 	delta_temp = sc->sc_temps[i].temp - temp0;
313 
314 	return code0 + (temp - temp0) * delta_code / delta_temp;
315 }
316 
317 int32_t
318 rktemp_calc_temp(struct rktemp_softc *sc, int32_t code)
319 {
320 	const int n = sc->sc_ntemps;
321 	int32_t code0, delta_code;
322 	int32_t temp0, delta_temp;
323 	int i;
324 
325 	/* Handle both negative and postive temperature coefficients. */
326 	if (sc->sc_temps[0].code > sc->sc_temps[1].code) {
327 		if (code >= sc->sc_temps[0].code)
328 			return sc->sc_temps[0].code;
329 		if (code <= sc->sc_temps[n - 1].code)
330 			return sc->sc_temps[n - 1].temp;
331 
332 		for (i = 1; i < n; i++) {
333 			if (code > sc->sc_temps[i].code)
334 				break;
335 		}
336 	} else {
337 		if (code <= sc->sc_temps[0].code)
338 			return sc->sc_temps[0].temp;
339 		if (code >= sc->sc_temps[n - 1].code)
340 			return sc->sc_temps[n - 1].temp;
341 
342 		for (i = 1; i < n; i++) {
343 			if (code < sc->sc_temps[i].code)
344 				break;
345 		}
346 	}
347 
348 	code0 = sc->sc_temps[i - 1].code;
349 	temp0 = sc->sc_temps[i - 1].temp;
350 	delta_code = sc->sc_temps[i].code - code0;
351 	delta_temp = sc->sc_temps[i].temp - temp0;
352 
353 	return temp0 + (code - code0) * delta_temp / delta_code;
354 }
355 
356 int
357 rktemp_valid(struct rktemp_softc *sc, int32_t code)
358 {
359 	const int n = sc->sc_ntemps;
360 
361 	if (sc->sc_temps[0].code > sc->sc_temps[1].code) {
362 		if (code > sc->sc_temps[0].code)
363 			return 0;
364 		if (code < sc->sc_temps[n - 1].code)
365 			return 0;
366 	} else {
367 		if (code < sc->sc_temps[0].code)
368 			return 0;
369 		if (code > sc->sc_temps[n - 1].code)
370 			return 0;
371 	}
372 	return 1;
373 }
374 
375 void
376 rktemp_refresh_sensors(void *arg)
377 {
378 	struct rktemp_softc *sc = arg;
379 	int32_t code, temp;
380 	int i;
381 
382 	for (i = 0; i < sc->sc_nsensors; i++) {
383 		code = HREAD4(sc, TSADC_DATA0 + i * 4);
384 		temp = rktemp_calc_temp(sc, code);
385 		sc->sc_sensors[i].value = 273150000 + 1000 * temp;
386 		if (rktemp_valid(sc, code))
387 			sc->sc_sensors[i].flags &= ~SENSOR_FINVALID;
388 		else
389 			sc->sc_sensors[i].flags |= SENSOR_FINVALID;
390 	}
391 }
392