xref: /openbsd-src/sys/dev/fdt/rktemp.c (revision c0dd97bfcad3dab6c31ec12b9de1274fd2d2f993)
1 /*	$OpenBSD: rktemp.c,v 1.1 2017/08/25 10:29:54 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_SRC1_EN		(1 << 5)
38 #define  TSADC_AUTO_CON_SRC0_EN		(1 << 4)
39 #define  TSADC_AUTO_CON_TSADC_Q_SEL	(1 << 1)
40 #define  TSADC_AUTO_CON_AUTO_EN		(1 << 0)
41 #define TSADC_INT_EN		0x0008
42 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC1	(1 << 9)
43 #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC0	(1 << 8)
44 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1	(1 << 5)
45 #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0	(1 << 4)
46 #define TSADC_INT_PD		0x000c
47 #define TSADC_DATA0		0x0020
48 #define TSADC_DATA1		0x0024
49 #define TSADC_COMP0_INT		0x0030
50 #define TSADC_COMP1_INT		0x0034
51 #define TSADC_COMP0_SHUT	0x0040
52 #define TSADC_COMP1_SHUT	0x0044
53 #define TSADC_AUTO_PERIOD	0x0068
54 #define TSADC_AUTO_PERIOD_HT	0x006c
55 
56 #define HREAD4(sc, reg)							\
57 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
58 #define HWRITE4(sc, reg, val)						\
59 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
60 
61 struct rktemp_softc {
62 	struct device		sc_dev;
63 	bus_space_tag_t		sc_iot;
64 	bus_space_handle_t	sc_ioh;
65 
66 	struct ksensor		sc_sensors[2];
67 	struct ksensordev	sc_sensordev;
68 };
69 
70 int	rktemp_match(struct device *, void *, void *);
71 void	rktemp_attach(struct device *, struct device *, void *);
72 
73 struct cfattach	rktemp_ca = {
74 	sizeof (struct rktemp_softc), rktemp_match, rktemp_attach
75 };
76 
77 struct cfdriver rktemp_cd = {
78 	NULL, "rktemp", DV_DULL
79 };
80 
81 uint32_t rktemp_calc_code(int32_t);
82 int32_t rktemp_calc_temp(uint32_t);
83 int	rktemp_valid(uint32_t);
84 void	rktemp_refresh_sensors(void *);
85 
86 int
87 rktemp_match(struct device *parent, void *match, void *aux)
88 {
89 	struct fdt_attach_args *faa = aux;
90 
91 	return (OF_is_compatible(faa->fa_node, "rockchip,rk3399-tsadc"));
92 }
93 
94 void
95 rktemp_attach(struct device *parent, struct device *self, void *aux)
96 {
97 	struct rktemp_softc *sc = (struct rktemp_softc *)self;
98 	struct fdt_attach_args *faa = aux;
99 	uint32_t mode, polarity, temp;
100 	uint32_t auto_con, int_en;
101 	int node = faa->fa_node;
102 
103 	if (faa->fa_nreg < 1) {
104 		printf(": no registers\n");
105 		return;
106 	}
107 
108 	sc->sc_iot = faa->fa_iot;
109 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
110 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
111 		printf(": can't map registers\n");
112 		return;
113 	}
114 
115 	printf("\n");
116 
117 	pinctrl_byname(node, "init");
118 
119 	clock_enable(node, "tsadc");
120 	clock_enable(node, "apb_pclk");
121 
122 	/* Reset the TS-ADC controller block. */
123 	reset_assert(node, "tsadc-apb");
124 	delay(10);
125 	reset_deassert(node, "tsadc-apb");
126 
127 	mode = OF_getpropint(node, "rockchip,hw-tshut-mode", 1);
128 	polarity = OF_getpropint(node, "rockchip,hw-tshut-polarity", 0);
129 	temp = OF_getpropint(node, "rockchip,hw-tshut-temp", 95000);
130 
131 	auto_con = HREAD4(sc, TSADC_AUTO_CON);
132 	auto_con |= TSADC_AUTO_CON_TSADC_Q_SEL;
133 	if (polarity)
134 		auto_con |= TSADC_AUTO_CON_TSHUT_POLARITY;
135 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
136 
137 	/* Configure mode. */
138 	int_en = HREAD4(sc, TSADC_INT_EN);
139 	if (mode) {
140 		int_en |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0;
141 		int_en |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1;
142 	} else {
143 		int_en |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC0;
144 		int_en |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC1;
145 	}
146 	HWRITE4(sc, TSADC_INT_EN, int_en);
147 
148 	/* Set shutdown limit. */
149 	HWRITE4(sc, TSADC_COMP0_SHUT, rktemp_calc_code(temp));
150 	auto_con |= TSADC_AUTO_CON_SRC0_EN;
151 	HWRITE4(sc, TSADC_COMP1_SHUT, rktemp_calc_code(temp));
152 	auto_con |= TSADC_AUTO_CON_SRC1_EN;
153 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
154 
155 	pinctrl_byname(faa->fa_node, "default");
156 
157 	/* Finally turn on the ADC. */
158 	auto_con |= TSADC_AUTO_CON_AUTO_EN;
159 	HWRITE4(sc, TSADC_AUTO_CON, auto_con);
160 
161 	/* Register sensors. */
162 	strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
163 	    sizeof(sc->sc_sensordev.xname));
164 	strlcpy(sc->sc_sensors[0].desc, "CPU", sizeof(sc->sc_sensors[0].desc));
165 	sc->sc_sensors[0].type = SENSOR_TEMP;
166 	sc->sc_sensors[0].flags = SENSOR_FINVALID;
167 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[0]);
168 	strlcpy(sc->sc_sensors[1].desc, "GPU", sizeof(sc->sc_sensors[1].desc));
169 	sc->sc_sensors[1].type = SENSOR_TEMP;
170 	sc->sc_sensors[1].flags = SENSOR_FINVALID;
171 	sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[1]);
172 	sensordev_install(&sc->sc_sensordev);
173 	sensor_task_register(sc, rktemp_refresh_sensors, 5);
174 }
175 
176 struct rktemp_table_entry {
177 	int32_t temp;
178 	uint32_t code;
179 };
180 
181 /* RK3399 conversion table. */
182 struct rktemp_table_entry rktemp_table[] = {
183 	{ -40000, 402 },
184 	{ -35000, 410 },
185 	{ -30000, 419 },
186 	{ -25000, 427 },
187 	{ -20000, 436 },
188 	{ -15000, 444 },
189 	{ -10000, 453 },
190 	{  -5000, 461 },
191 	{      0, 470 },
192 	{   5000, 478 },
193 	{  10000, 487 },
194 	{  15000, 496 },
195 	{  20000, 504 },
196 	{  25000, 513 },
197 	{  30000, 521 },
198 	{  35000, 530 },
199 	{  40000, 538 },
200 	{  45000, 547 },
201 	{  50000, 555 },
202 	{  55000, 564 },
203 	{  60000, 573 },
204 	{  65000, 581 },
205 	{  70000, 590 },
206 	{  75000, 599 },
207 	{  80000, 607 },
208 	{  85000, 616 },
209 	{  90000, 624 },
210 	{  95000, 633 },
211 	{ 100000, 642 },
212 	{ 105000, 650 },
213 	{ 110000, 659 },
214 	{ 115000, 668 },
215 	{ 120000, 677 },
216 	{ 125000, 685 }
217 };
218 
219 uint32_t
220 rktemp_calc_code(int32_t temp)
221 {
222 	const int n = nitems(rktemp_table);
223 	uint32_t code0, delta_code;
224 	int32_t temp0, delta_temp;
225 	int i;
226 
227 	if (temp <= rktemp_table[0].temp)
228 		return rktemp_table[0].code;
229 	if (temp >= rktemp_table[n - 1].temp)
230 		return rktemp_table[n - 1].code;
231 
232 	for (i = 1; i < n; i++) {
233 		if (temp < rktemp_table[i].temp)
234 			break;
235 	}
236 
237 	code0 = rktemp_table[i - 1].code;
238 	temp0 = rktemp_table[i - 1].temp;
239 	delta_code = rktemp_table[i].code - code0;
240 	delta_temp = rktemp_table[i].temp - temp0;
241 
242 	return code0 + (temp - temp0) * delta_code / delta_temp;
243 }
244 
245 int32_t
246 rktemp_calc_temp(uint32_t code)
247 {
248 	const int n = nitems(rktemp_table);
249 	uint32_t code0, delta_code;
250 	int32_t temp0, delta_temp;
251 	int i;
252 
253 	if (code <= rktemp_table[0].code)
254 		return rktemp_table[0].temp;
255 	if (code >= rktemp_table[n - 1].code)
256 		return rktemp_table[n - 1].temp;
257 
258 	for (i = 1; i < n; i++) {
259 		if (code < rktemp_table[i].code)
260 			break;
261 	}
262 
263 	code0 = rktemp_table[i - 1].code;
264 	temp0 = rktemp_table[i - 1].temp;
265 	delta_code = rktemp_table[i].code - code0;
266 	delta_temp = rktemp_table[i].temp - temp0;
267 
268 	return temp0 + (code - code0) * delta_temp / delta_code;
269 }
270 
271 int
272 rktemp_valid(uint32_t code)
273 {
274 	const int n = nitems(rktemp_table);
275 
276 	if (code < rktemp_table[0].code)
277 		return 0;
278 	if (code > rktemp_table[n - 1].code)
279 		return 0;
280 	return 1;
281 }
282 
283 void
284 rktemp_refresh_sensors(void *arg)
285 {
286 	struct rktemp_softc *sc = arg;
287 	uint32_t code;
288 
289 	code = HREAD4(sc, TSADC_DATA0);
290 	sc->sc_sensors[0].value = 1000 * rktemp_calc_temp(code) + 273150000;
291 	if (rktemp_valid(code))
292 		sc->sc_sensors[0].flags &= ~SENSOR_FINVALID;
293 	else
294 		sc->sc_sensors[0].flags |= SENSOR_FINVALID;
295 
296 	code = HREAD4(sc, TSADC_DATA1);
297 	sc->sc_sensors[1].value = 1000 * rktemp_calc_temp(code) + 273150000;
298 	if (rktemp_valid(code))
299 		sc->sc_sensors[1].flags &= ~SENSOR_FINVALID;
300 	else
301 		sc->sc_sensors[1].flags |= SENSOR_FINVALID;
302 }
303