xref: /freebsd/sys/arm/nvidia/tegra_soctherm.c (revision eac7052fdebb90caf2f653e06187bdbca837b9c7)
1 /*-
2  * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 /*
31  * Thermometer and thermal zones driver for Tegra SoCs.
32  * Calibration data and algo are taken from Linux, because this part of SoC
33  * is undocumented in TRM.
34  */
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/gpio.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/malloc.h>
43 #include <sys/rman.h>
44 #include <sys/sysctl.h>
45 
46 #include <machine/bus.h>
47 
48 #include <dev/extres/clk/clk.h>
49 #include <dev/extres/hwreset/hwreset.h>
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52 
53 #include <arm/nvidia/tegra_efuse.h>
54 #include <gnu/dts/include/dt-bindings/thermal/tegra124-soctherm.h>
55 #include "tegra_soctherm_if.h"
56 
57 /* Per sensors registers - base is 0x0c0*/
58 #define	TSENSOR_CONFIG0				0x000
59 #define	 TSENSOR_CONFIG0_TALL(x)			(((x) & 0xFFFFF) << 8)
60 #define	 TSENSOR_CONFIG0_STATUS_CLR			(1 << 5)
61 #define	 TSENSOR_CONFIG0_TCALC_OVERFLOW			(1 << 4)
62 #define	 TSENSOR_CONFIG0_OVERFLOW			(1 << 3)
63 #define	 TSENSOR_CONFIG0_CPTR_OVERFLOW			(1 << 2)
64 #define	 TSENSOR_CONFIG0_RO_SEL				(1 << 1)
65 #define	 TSENSOR_CONFIG0_STOP				(1 << 0)
66 
67 #define	TSENSOR_CONFIG1				0x004
68 #define	 TSENSOR_CONFIG1_TEMP_ENABLE			(1U << 31)
69 #define	 TSENSOR_CONFIG1_TEN_COUNT(x)			(((x) & 0x3F) << 24)
70 #define	 TSENSOR_CONFIG1_TIDDQ_EN(x)			(((x) & 0x3F) << 15)
71 #define	 TSENSOR_CONFIG1_TSAMPLE(x)			(((x) & 0x3FF) << 0)
72 
73 #define	TSENSOR_CONFIG2				0x008
74 #define	TSENSOR_CONFIG2_THERMA(x)			(((x) & 0xFFFF) << 16)
75 #define	TSENSOR_CONFIG2_THERMB(x)			(((x) & 0xFFFF) << 0)
76 
77 #define	TSENSOR_STATUS0				0x00c
78 #define	 TSENSOR_STATUS0_CAPTURE_VALID			(1U << 31)
79 #define	 TSENSOR_STATUS0_CAPTURE(x)			(((x) >> 0) & 0xffff)
80 
81 #define	TSENSOR_STATUS1				0x010
82 #define	 TSENSOR_STATUS1_TEMP_VALID			(1U << 31)
83 #define	 TSENSOR_STATUS1_TEMP(x)			(((x) >> 0) & 0xffff)
84 
85 #define	TSENSOR_STATUS2				0x014
86 #define	 TSENSOR_STATUS2_TEMP_MAX(x)			(((x) >> 16) & 0xffff)
87 #define	 TSENSOR_STATUS2_TEMP_MIN(x)			(((x) >>  0) & 0xffff)
88 
89 /* Global registers */
90 #define	TSENSOR_PDIV				0x1c0
91 #define	 TSENSOR_PDIV_T124				0x8888
92 #define	TSENSOR_HOTSPOT_OFF			0x1c4
93 #define	 TSENSOR_HOTSPOT_OFF_T124			0x00060600
94 #define	TSENSOR_TEMP1				0x1c8
95 #define	TSENSOR_TEMP2				0x1cc
96 
97 /* Readbacks */
98 #define	READBACK_VALUE_MASK				0xff00
99 #define	READBACK_VALUE_SHIFT				8
100 #define	READBACK_ADD_HALF				(1 << 7)
101 #define	READBACK_NEGATE					(1 << 0)
102 
103 /* Fuses */
104 #define	 FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT		0
105 #define	 FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS		13
106 #define	 FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT		13
107 #define	 FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS		13
108 
109 #define	FUSE_TSENSOR8_CALIB			0x180
110 #define	 FUSE_TSENSOR8_CALIB_CP_TS_BASE(x)		(((x) >>  0) & 0x3ff)
111 #define	 FUSE_TSENSOR8_CALIB_FT_TS_BASE(x)		(((x) >> 10) & 0x7ff)
112 
113 #define	FUSE_SPARE_REALIGNMENT_REG		0x1fc
114 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT 	0
115 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS 	6
116 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 	21
117 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS 	5
118 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP(x) 	(((x) >>  0) & 0x3f)
119 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT(x) 	(((x) >> 21) & 0x1f)
120 
121 #define	NOMINAL_CALIB_FT_T124	105
122 #define	NOMINAL_CALIB_CP_T124	25
123 
124 #define	WR4(_sc, _r, _v)	bus_write_4((_sc)->mem_res, (_r), (_v))
125 #define	RD4(_sc, _r)		bus_read_4((_sc)->mem_res, (_r))
126 
127 static struct sysctl_ctx_list soctherm_sysctl_ctx;
128 
129 struct soctherm_shared_cal {
130 	uint32_t		base_cp;
131 	uint32_t		base_ft;
132 	int32_t			actual_temp_cp;
133 	int32_t			actual_temp_ft;
134 };
135 struct tsensor_cfg {
136 	uint32_t		tall;
137 	uint32_t		tsample;
138 	uint32_t		tiddq_en;
139 	uint32_t		ten_count;
140 	uint32_t		pdiv;
141 	uint32_t		tsample_ate;
142 	uint32_t		pdiv_ate;
143 };
144 
145 struct tsensor {
146 	char 			*name;
147 	int			id;
148 	struct tsensor_cfg 	*cfg;
149 	bus_addr_t		sensor_base;
150 	bus_addr_t		calib_fuse;
151 	int 			fuse_corr_alpha;
152 	int			fuse_corr_beta;
153 
154 	int16_t			therm_a;
155 	int16_t			therm_b;
156 };
157 
158 struct soctherm_softc {
159 	device_t		dev;
160 	struct resource		*mem_res;
161 	struct resource		*irq_res;
162 	void			*irq_ih;
163 
164 	clk_t			tsensor_clk;
165 	clk_t			soctherm_clk;
166 	hwreset_t			reset;
167 
168 	int			ntsensors;
169 	struct tsensor		*tsensors;
170 };
171 
172 static struct ofw_compat_data compat_data[] = {
173 	{"nvidia,tegra124-soctherm",	1},
174 	{NULL,				0},
175 };
176 
177 static struct tsensor_cfg t124_tsensor_config = {
178 	.tall = 16300,
179 	.tsample = 120,
180 	.tiddq_en = 1,
181 	.ten_count = 1,
182 	.pdiv = 8,
183 	.tsample_ate = 480,
184 	.pdiv_ate = 8
185 };
186 
187 static struct tsensor t124_tsensors[] = {
188 	{
189 		.name = "cpu0",
190 		.id = TEGRA124_SOCTHERM_SENSOR_CPU,
191 		.cfg = &t124_tsensor_config,
192 		.sensor_base = 0x0c0,
193 		.calib_fuse = 0x098,
194 		.fuse_corr_alpha = 1135400,
195 		.fuse_corr_beta = -6266900,
196 	},
197 	{
198 		.name = "cpu1",
199 		.id = -1,
200 		.cfg = &t124_tsensor_config,
201 		.sensor_base = 0x0e0,
202 		.calib_fuse = 0x084,
203 		.fuse_corr_alpha = 1122220,
204 		.fuse_corr_beta = -5700700,
205 	},
206 	{
207 		.name = "cpu2",
208 		.id = -1,
209 		.cfg = &t124_tsensor_config,
210 		.sensor_base = 0x100,
211 		.calib_fuse = 0x088,
212 		.fuse_corr_alpha = 1127000,
213 		.fuse_corr_beta = -6768200,
214 	},
215 	{
216 		.name = "cpu3",
217 		.id = -1,
218 		.cfg = &t124_tsensor_config,
219 		.sensor_base = 0x120,
220 		.calib_fuse = 0x12c,
221 		.fuse_corr_alpha = 1110900,
222 		.fuse_corr_beta = -6232000,
223 	},
224 	{
225 		.name = "mem0",
226 		.id = TEGRA124_SOCTHERM_SENSOR_MEM,
227 		.cfg = &t124_tsensor_config,
228 		.sensor_base = 0x140,
229 		.calib_fuse = 0x158,
230 		.fuse_corr_alpha = 1122300,
231 		.fuse_corr_beta = -5936400,
232 	},
233 	{
234 		.name = "mem1",
235 		.id = -1,
236 		.cfg = &t124_tsensor_config,
237 		.sensor_base = 0x160,
238 		.calib_fuse = 0x15c,
239 		.fuse_corr_alpha = 1145700,
240 		.fuse_corr_beta = -7124600,
241 	},
242 	{
243 		.name = "gpu",
244 		.id = TEGRA124_SOCTHERM_SENSOR_GPU,
245 		.cfg = &t124_tsensor_config,
246 		.sensor_base = 0x180,
247 		.calib_fuse = 0x154,
248 		.fuse_corr_alpha = 1120100,
249 		.fuse_corr_beta = -6000500,
250 	},
251 	{
252 		.name = "pllX",
253 		.id = TEGRA124_SOCTHERM_SENSOR_PLLX,
254 		.cfg = &t124_tsensor_config,
255 		.sensor_base = 0x1a0,
256 		.calib_fuse = 0x160,
257 		.fuse_corr_alpha = 1106500,
258 		.fuse_corr_beta = -6729300,
259 	},
260 };
261 
262 /* Extract signed integer bitfield from register */
263 static int
264 extract_signed(uint32_t reg, int shift, int bits)
265 {
266 	int32_t val;
267 	uint32_t mask;
268 
269 	mask = (1 << bits) - 1;
270 	val = ((reg >> shift) & mask) << (32 - bits);
271 	val >>= 32 - bits;
272 	return ((int32_t)val);
273 }
274 
275 static inline int64_t div64_s64_precise(int64_t a, int64_t b)
276 {
277 	int64_t r, al;
278 
279 	al = a << 16;
280 	r = (al * 2 + 1) / (2 * b);
281 	return r >> 16;
282 }
283 
284 static void
285 get_shared_cal(struct soctherm_softc *sc, struct soctherm_shared_cal *cal)
286 {
287 	uint32_t val;
288 	int calib_cp, calib_ft;
289 
290 	val = tegra_fuse_read_4(FUSE_TSENSOR8_CALIB);
291 	cal->base_cp = FUSE_TSENSOR8_CALIB_CP_TS_BASE(val);
292 	cal->base_ft = FUSE_TSENSOR8_CALIB_FT_TS_BASE(val);
293 
294 	val = tegra_fuse_read_4(FUSE_SPARE_REALIGNMENT_REG);
295 	calib_ft = extract_signed(val,
296 	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT,
297 	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS);
298 	calib_cp = extract_signed(val,
299 	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT,
300 	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS);
301 
302 	cal->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + calib_cp;
303 	cal->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + calib_ft;
304 #ifdef DEBUG
305 	printf("%s: base_cp: %u, base_ft: %d,"
306 	    " actual_temp_cp: %d, actual_temp_ft: %d\n",
307 	    __func__, cal->base_cp, cal->base_ft,
308 	    cal->actual_temp_cp, cal->actual_temp_ft);
309 #endif
310 }
311 
312 static void
313 tsensor_calibration(struct tsensor *sensor, struct soctherm_shared_cal *shared)
314 {
315 	uint32_t val;
316 	int mult, div, calib_cp, calib_ft;
317 	int actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp;
318 	int temp_a, temp_b;
319 	int64_t tmp;
320 
321 	val =  tegra_fuse_read_4(sensor->calib_fuse);
322 	calib_cp = extract_signed(val,
323 	    FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT,
324 	    FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS);
325 	actual_tsensor_cp = shared->base_cp * 64 + calib_cp;
326 
327 	calib_ft = extract_signed(val,
328 	    FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT,
329 	    FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS);
330 	actual_tsensor_ft = shared->base_ft * 32 + calib_ft;
331 
332 	delta_sens = actual_tsensor_ft - actual_tsensor_cp;
333 	delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
334 	mult = sensor->cfg->pdiv * sensor->cfg->tsample_ate;
335 	div = sensor->cfg->tsample * sensor->cfg->pdiv_ate;
336 
337 	temp_a = div64_s64_precise((int64_t) delta_temp * (1LL << 13) * mult,
338 				   (int64_t) delta_sens * div);
339 
340 	tmp = (int64_t)actual_tsensor_ft * shared->actual_temp_cp -
341 	      (int64_t)actual_tsensor_cp * shared->actual_temp_ft;
342 	temp_b = div64_s64_precise(tmp, (int64_t)delta_sens);
343 
344 	temp_a = div64_s64_precise((int64_t)temp_a * sensor->fuse_corr_alpha,
345 				   1000000);
346 	temp_b = div64_s64_precise((int64_t)temp_b * sensor->fuse_corr_alpha +
347 				   sensor->fuse_corr_beta, 1000000);
348 	sensor->therm_a = (int16_t)temp_a;
349 	sensor->therm_b = (int16_t)temp_b;
350 #ifdef DEBUG
351 	printf("%s: sensor %s fuse: 0x%08X (0x%04X, 0x%04X)"
352 	    " calib_cp: %d(0x%04X), calib_ft: %d(0x%04X)\n",
353 	    __func__, sensor->name, val, val & 0x1FFF, (val >> 13) & 0x1FFF,
354 	    calib_cp, calib_cp, calib_ft, calib_ft);
355 	printf("therma: 0x%04X(%d), thermb: 0x%04X(%d)\n",
356 	    (uint16_t)sensor->therm_a, temp_a,
357 	    (uint16_t)sensor->therm_b, sensor->therm_b);
358 #endif
359 }
360 
361 static void
362 soctherm_init_tsensor(struct soctherm_softc *sc, struct tsensor *sensor,
363     struct soctherm_shared_cal *shared_cal)
364 {
365 	uint32_t val;
366 
367 	tsensor_calibration(sensor, shared_cal);
368 
369 	val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
370 	val |= TSENSOR_CONFIG0_STOP;
371 	val |= TSENSOR_CONFIG0_STATUS_CLR;
372 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
373 
374 	val = TSENSOR_CONFIG0_TALL(sensor->cfg->tall);
375 	val |= TSENSOR_CONFIG0_STOP;
376 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
377 
378 	val = TSENSOR_CONFIG1_TSAMPLE(sensor->cfg->tsample - 1);
379 	val |= TSENSOR_CONFIG1_TIDDQ_EN(sensor->cfg->tiddq_en);
380 	val |= TSENSOR_CONFIG1_TEN_COUNT(sensor->cfg->ten_count);
381 	val |= TSENSOR_CONFIG1_TEMP_ENABLE;
382 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG1, val);
383 
384 	val = TSENSOR_CONFIG2_THERMA((uint16_t)sensor->therm_a) |
385 	     TSENSOR_CONFIG2_THERMB((uint16_t)sensor->therm_b);
386 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG2, val);
387 
388 	val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
389 	val &= ~TSENSOR_CONFIG0_STOP;
390 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
391 #ifdef DEBUG
392 	printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
393 	    " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
394 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
395 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
396 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
397 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
398 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
399 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
400 	    );
401 #endif
402 }
403 
404 static int
405 soctherm_convert_raw(uint32_t val)
406 {
407 	int32_t t;
408 
409 	t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
410 	if (val & READBACK_ADD_HALF)
411 		t += 500;
412 	if (val & READBACK_NEGATE)
413 		t *= -1;
414 
415 	return t;
416 }
417 
418 static int
419 soctherm_read_temp(struct soctherm_softc *sc, struct tsensor *sensor, int *temp)
420 {
421 	int timeout;
422 	uint32_t val;
423 
424 	/* wait for valid sample */
425 	for (timeout = 1000; timeout > 0; timeout--) {
426 		val = RD4(sc, sensor->sensor_base + TSENSOR_STATUS1);
427 		if ((val & TSENSOR_STATUS1_TEMP_VALID) != 0)
428 			break;
429 		DELAY(100);
430 	}
431 	if (timeout <= 0)
432 		device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
433 	*temp = soctherm_convert_raw(val);
434 #ifdef DEBUG
435 	printf("%s: Raw: 0x%08X, temp: %d\n", __func__, val, *temp);
436 	printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
437 	    " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
438 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
439 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
440 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
441 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
442 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
443 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
444 	    );
445 #endif
446 	return 0;
447 }
448 
449 static int
450 soctherm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
451 {
452 	struct soctherm_softc *sc;
453 	int i;
454 
455 	sc = device_get_softc(dev);
456 	/* The direct sensor map starts at 0x100 */
457 	if (id >= 0x100) {
458 		id -= 0x100;
459 		if (id >= sc->ntsensors)
460 			return (ERANGE);
461 		return(soctherm_read_temp(sc, sc->tsensors + id, val));
462 	}
463 	/* Linux (DT) compatible thermal zones */
464 	for (i = 0; i < sc->ntsensors; i++) {
465 		if (sc->tsensors->id == id)
466 			return(soctherm_read_temp(sc, sc->tsensors + id, val));
467 	}
468 	return (ERANGE);
469 }
470 
471 static int
472 soctherm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
473 {
474 	struct soctherm_softc *sc;
475 	int val;
476 	int rv;
477 	int id;
478 
479 	/* Write request */
480 	if (req->newptr != NULL)
481 		return (EINVAL);
482 
483 	sc = arg1;
484 	id = arg2;
485 
486 	if (id >= sc->ntsensors)
487 		return (ERANGE);
488 	rv =  soctherm_read_temp(sc, sc->tsensors + id, &val);
489 	if (rv != 0)
490 		return (rv);
491 
492 	val = val / 100;
493 	val +=  2731;
494 	rv = sysctl_handle_int(oidp, &val, 0, req);
495 	return (rv);
496 }
497 
498 static int
499 soctherm_init_sysctl(struct soctherm_softc *sc)
500 {
501 	int i;
502 	struct sysctl_oid *oid, *tmp;
503 
504 	sysctl_ctx_init(&soctherm_sysctl_ctx);
505 	/* create node for hw.temp */
506 	oid = SYSCTL_ADD_NODE(&soctherm_sysctl_ctx,
507 	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
508 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
509 	if (oid == NULL)
510 		return (ENXIO);
511 
512 	/* Add sensors */
513 	for (i = sc->ntsensors  - 1; i >= 0; i--) {
514 		tmp = SYSCTL_ADD_PROC(&soctherm_sysctl_ctx,
515 		    SYSCTL_CHILDREN(oid), OID_AUTO, sc->tsensors[i].name,
516 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, i,
517 		    soctherm_sysctl_temperature, "IK", "SoC Temperature");
518 		if (tmp == NULL)
519 			return (ENXIO);
520 	}
521 
522 	return (0);
523 }
524 
525 static int
526 soctherm_probe(device_t dev)
527 {
528 
529 	if (!ofw_bus_status_okay(dev))
530 		return (ENXIO);
531 
532 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
533 		return (ENXIO);
534 
535 	device_set_desc(dev, "Tegra temperature sensors");
536 	return (BUS_PROBE_DEFAULT);
537 }
538 
539 static int
540 soctherm_attach(device_t dev)
541 {
542 	struct soctherm_softc *sc;
543 	phandle_t node;
544 	int i, rid, rv;
545 	struct soctherm_shared_cal shared_calib;
546 
547 	sc = device_get_softc(dev);
548 	sc->dev = dev;
549 	node = ofw_bus_get_node(sc->dev);
550 
551 	rid = 0;
552 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
553 	    RF_ACTIVE);
554 	if (sc->mem_res == NULL) {
555 		device_printf(dev, "Cannot allocate memory resources\n");
556 		goto fail;
557 	}
558 
559 	rid = 0;
560 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
561 	if (sc->irq_res == NULL) {
562 		device_printf(dev, "Cannot allocate IRQ resources\n");
563 		goto fail;
564 	}
565 
566 /*
567 	if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
568 	    soctherm_intr, NULL, sc, &sc->irq_ih))) {
569 		device_printf(dev,
570 		    "WARNING: unable to register interrupt handler\n");
571 		goto fail;
572 	}
573 */
574 
575 	/* OWF resources */
576 	rv = hwreset_get_by_ofw_name(dev, 0, "soctherm", &sc->reset);
577 	if (rv != 0) {
578 		device_printf(dev, "Cannot get fuse reset\n");
579 		goto fail;
580 	}
581 	rv = clk_get_by_ofw_name(dev, 0, "tsensor", &sc->tsensor_clk);
582 	if (rv != 0) {
583 		device_printf(dev, "Cannot get 'tsensor' clock: %d\n", rv);
584 		goto fail;
585 	}
586 	rv = clk_get_by_ofw_name(dev, 0, "soctherm", &sc->soctherm_clk);
587 	if (rv != 0) {
588 		device_printf(dev, "Cannot get 'soctherm' clock: %d\n", rv);
589 		goto fail;
590 	}
591 
592 	rv = hwreset_assert(sc->reset);
593 	if (rv != 0) {
594 		device_printf(dev, "Cannot assert reset\n");
595 		goto fail;
596 	}
597 	rv = clk_enable(sc->tsensor_clk);
598 	if (rv != 0) {
599 		device_printf(dev, "Cannot enable 'tsensor' clock: %d\n", rv);
600 		goto fail;
601 	}
602 	rv = clk_enable(sc->soctherm_clk);
603 	if (rv != 0) {
604 		device_printf(dev, "Cannot enable 'soctherm' clock: %d\n", rv);
605 		goto fail;
606 	}
607 	rv = hwreset_deassert(sc->reset);
608 	if (rv != 0) {
609 		device_printf(dev, "Cannot clear reset\n");
610 		goto fail;
611 	}
612 
613 	/* Tegra 124 */
614 	sc->tsensors = t124_tsensors;
615 	sc->ntsensors = nitems(t124_tsensors);
616 	get_shared_cal(sc, &shared_calib);
617 
618 	WR4(sc, TSENSOR_PDIV, TSENSOR_PDIV_T124);
619 	WR4(sc, TSENSOR_HOTSPOT_OFF, TSENSOR_HOTSPOT_OFF_T124);
620 
621 	for (i = 0; i < sc->ntsensors; i++)
622 		soctherm_init_tsensor(sc, sc->tsensors + i, &shared_calib);
623 
624 	rv = soctherm_init_sysctl(sc);
625 	if (rv != 0) {
626 		device_printf(sc->dev, "Cannot initialize sysctls\n");
627 		goto fail;
628 	}
629 
630 	OF_device_register_xref(OF_xref_from_node(node), dev);
631 	return (bus_generic_attach(dev));
632 
633 fail:
634 	if (sc->irq_ih != NULL)
635 		bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
636 	sysctl_ctx_free(&soctherm_sysctl_ctx);
637 	if (sc->tsensor_clk != NULL)
638 		clk_release(sc->tsensor_clk);
639 	if (sc->soctherm_clk != NULL)
640 		clk_release(sc->soctherm_clk);
641 	if (sc->reset != NULL)
642 		hwreset_release(sc->reset);
643 	if (sc->irq_res != NULL)
644 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
645 	if (sc->mem_res != NULL)
646 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
647 
648 	return (ENXIO);
649 }
650 
651 static int
652 soctherm_detach(device_t dev)
653 {
654 	struct soctherm_softc *sc;
655 	sc = device_get_softc(dev);
656 
657 	if (sc->irq_ih != NULL)
658 		bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
659 	sysctl_ctx_free(&soctherm_sysctl_ctx);
660 	if (sc->tsensor_clk != NULL)
661 		clk_release(sc->tsensor_clk);
662 	if (sc->soctherm_clk != NULL)
663 		clk_release(sc->soctherm_clk);
664 	if (sc->reset != NULL)
665 		hwreset_release(sc->reset);
666 	if (sc->irq_res != NULL)
667 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
668 	if (sc->mem_res != NULL)
669 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
670 
671 	return (ENXIO);
672 }
673 
674 static device_method_t tegra_soctherm_methods[] = {
675 	/* Device interface */
676 	DEVMETHOD(device_probe,			soctherm_probe),
677 	DEVMETHOD(device_attach,		soctherm_attach),
678 	DEVMETHOD(device_detach,		soctherm_detach),
679 
680 	/* SOCTHERM interface */
681 	DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
682 
683 	DEVMETHOD_END
684 };
685 
686 static devclass_t tegra_soctherm_devclass;
687 static DEFINE_CLASS_0(soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
688     sizeof(struct soctherm_softc));
689 EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,
690     tegra_soctherm_devclass, NULL, NULL, 79);
691