xref: /freebsd/sys/arm/nvidia/tegra_soctherm.c (revision d65cd7a57bf0600b722afc770838a5d0c1c3a8e1)
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 
104 /* Fuses */
105 #define	 FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT		0
106 #define	 FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS		13
107 #define	 FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT		13
108 #define	 FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS		13
109 
110 #define	FUSE_TSENSOR8_CALIB			0x180
111 #define	 FUSE_TSENSOR8_CALIB_CP_TS_BASE(x)		(((x) >>  0) & 0x3ff)
112 #define	 FUSE_TSENSOR8_CALIB_FT_TS_BASE(x)		(((x) >> 10) & 0x7ff)
113 
114 #define	FUSE_SPARE_REALIGNMENT_REG		0x1fc
115 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT 	0
116 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS 	6
117 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT 	21
118 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS 	5
119 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP(x) 	(((x) >>  0) & 0x3f)
120 #define	 FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT(x) 	(((x) >> 21) & 0x1f)
121 
122 
123 #define	NOMINAL_CALIB_FT_T124	105
124 #define	NOMINAL_CALIB_CP_T124	25
125 
126 #define	WR4(_sc, _r, _v)	bus_write_4((_sc)->mem_res, (_r), (_v))
127 #define	RD4(_sc, _r)		bus_read_4((_sc)->mem_res, (_r))
128 
129 static struct sysctl_ctx_list soctherm_sysctl_ctx;
130 
131 struct soctherm_shared_cal {
132 	uint32_t		base_cp;
133 	uint32_t		base_ft;
134 	int32_t			actual_temp_cp;
135 	int32_t			actual_temp_ft;
136 };
137 struct tsensor_cfg {
138 	uint32_t		tall;
139 	uint32_t		tsample;
140 	uint32_t		tiddq_en;
141 	uint32_t		ten_count;
142 	uint32_t		pdiv;
143 	uint32_t		tsample_ate;
144 	uint32_t		pdiv_ate;
145 };
146 
147 struct tsensor {
148 	char 			*name;
149 	int			id;
150 	struct tsensor_cfg 	*cfg;
151 	bus_addr_t		sensor_base;
152 	bus_addr_t		calib_fuse;
153 	int 			fuse_corr_alpha;
154 	int			fuse_corr_beta;
155 
156 	int16_t			therm_a;
157 	int16_t			therm_b;
158 };
159 
160 struct soctherm_softc {
161 	device_t		dev;
162 	struct resource		*mem_res;
163 	struct resource		*irq_res;
164 	void			*irq_ih;
165 
166 	clk_t			tsensor_clk;
167 	clk_t			soctherm_clk;
168 	hwreset_t			reset;
169 
170 	int			ntsensors;
171 	struct tsensor		*tsensors;
172 };
173 
174 static struct ofw_compat_data compat_data[] = {
175 	{"nvidia,tegra124-soctherm",	1},
176 	{NULL,				0},
177 };
178 
179 static struct tsensor_cfg t124_tsensor_config = {
180 	.tall = 16300,
181 	.tsample = 120,
182 	.tiddq_en = 1,
183 	.ten_count = 1,
184 	.pdiv = 8,
185 	.tsample_ate = 480,
186 	.pdiv_ate = 8
187 };
188 
189 
190 static struct tsensor t124_tsensors[] = {
191 	{
192 		.name = "cpu0",
193 		.id = TEGRA124_SOCTHERM_SENSOR_CPU,
194 		.cfg = &t124_tsensor_config,
195 		.sensor_base = 0x0c0,
196 		.calib_fuse = 0x098,
197 		.fuse_corr_alpha = 1135400,
198 		.fuse_corr_beta = -6266900,
199 	},
200 	{
201 		.name = "cpu1",
202 		.id = -1,
203 		.cfg = &t124_tsensor_config,
204 		.sensor_base = 0x0e0,
205 		.calib_fuse = 0x084,
206 		.fuse_corr_alpha = 1122220,
207 		.fuse_corr_beta = -5700700,
208 	},
209 	{
210 		.name = "cpu2",
211 		.id = -1,
212 		.cfg = &t124_tsensor_config,
213 		.sensor_base = 0x100,
214 		.calib_fuse = 0x088,
215 		.fuse_corr_alpha = 1127000,
216 		.fuse_corr_beta = -6768200,
217 	},
218 	{
219 		.name = "cpu3",
220 		.id = -1,
221 		.cfg = &t124_tsensor_config,
222 		.sensor_base = 0x120,
223 		.calib_fuse = 0x12c,
224 		.fuse_corr_alpha = 1110900,
225 		.fuse_corr_beta = -6232000,
226 	},
227 	{
228 		.name = "mem0",
229 		.id = TEGRA124_SOCTHERM_SENSOR_MEM,
230 		.cfg = &t124_tsensor_config,
231 		.sensor_base = 0x140,
232 		.calib_fuse = 0x158,
233 		.fuse_corr_alpha = 1122300,
234 		.fuse_corr_beta = -5936400,
235 	},
236 	{
237 		.name = "mem1",
238 		.id = -1,
239 		.cfg = &t124_tsensor_config,
240 		.sensor_base = 0x160,
241 		.calib_fuse = 0x15c,
242 		.fuse_corr_alpha = 1145700,
243 		.fuse_corr_beta = -7124600,
244 	},
245 	{
246 		.name = "gpu",
247 		.id = TEGRA124_SOCTHERM_SENSOR_GPU,
248 		.cfg = &t124_tsensor_config,
249 		.sensor_base = 0x180,
250 		.calib_fuse = 0x154,
251 		.fuse_corr_alpha = 1120100,
252 		.fuse_corr_beta = -6000500,
253 	},
254 	{
255 		.name = "pllX",
256 		.id = TEGRA124_SOCTHERM_SENSOR_PLLX,
257 		.cfg = &t124_tsensor_config,
258 		.sensor_base = 0x1a0,
259 		.calib_fuse = 0x160,
260 		.fuse_corr_alpha = 1106500,
261 		.fuse_corr_beta = -6729300,
262 	},
263 };
264 
265 /* Extract signed integer bitfield from register */
266 static int
267 extract_signed(uint32_t reg, int shift, int bits)
268 {
269 	int32_t val;
270 	uint32_t mask;
271 
272 	mask = (1 << bits) - 1;
273 	val = ((reg >> shift) & mask) << (32 - bits);
274 	val >>= 32 - bits;
275 	return ((int32_t)val);
276 }
277 
278 static inline int64_t div64_s64_precise(int64_t a, int64_t b)
279 {
280 	int64_t r, al;
281 
282 	al = a << 16;
283 	r = (al * 2 + 1) / (2 * b);
284 	return r >> 16;
285 }
286 
287 static void
288 get_shared_cal(struct soctherm_softc *sc, struct soctherm_shared_cal *cal)
289 {
290 	uint32_t val;
291 	int calib_cp, calib_ft;
292 
293 	val = tegra_fuse_read_4(FUSE_TSENSOR8_CALIB);
294 	cal->base_cp = FUSE_TSENSOR8_CALIB_CP_TS_BASE(val);
295 	cal->base_ft = FUSE_TSENSOR8_CALIB_FT_TS_BASE(val);
296 
297 	val = tegra_fuse_read_4(FUSE_SPARE_REALIGNMENT_REG);
298 	calib_ft = extract_signed(val,
299 	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_SHIFT,
300 	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_FT_BITS);
301 	calib_cp = extract_signed(val,
302 	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT,
303 	    FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS);
304 
305 	cal->actual_temp_cp = 2 * NOMINAL_CALIB_CP_T124 + calib_cp;
306 	cal->actual_temp_ft = 2 * NOMINAL_CALIB_FT_T124 + calib_ft;
307 #ifdef DEBUG
308 	printf("%s: base_cp: %u, base_ft: %d,"
309 	    " actual_temp_cp: %d, actual_temp_ft: %d\n",
310 	    __func__, cal->base_cp, cal->base_ft,
311 	    cal->actual_temp_cp, cal->actual_temp_ft);
312 #endif
313 }
314 
315 
316 static void
317 tsensor_calibration(struct tsensor *sensor, struct soctherm_shared_cal *shared)
318 {
319 	uint32_t val;
320 	int mult, div, calib_cp, calib_ft;
321 	int actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp;
322 	int temp_a, temp_b;
323 	int64_t tmp;
324 
325 	val =  tegra_fuse_read_4(sensor->calib_fuse);
326 	calib_cp = extract_signed(val,
327 	    FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT,
328 	    FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS);
329 	actual_tsensor_cp = shared->base_cp * 64 + calib_cp;
330 
331 	calib_ft = extract_signed(val,
332 	    FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT,
333 	    FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS);
334 	actual_tsensor_ft = shared->base_ft * 32 + calib_ft;
335 
336 	delta_sens = actual_tsensor_ft - actual_tsensor_cp;
337 	delta_temp = shared->actual_temp_ft - shared->actual_temp_cp;
338 	mult = sensor->cfg->pdiv * sensor->cfg->tsample_ate;
339 	div = sensor->cfg->tsample * sensor->cfg->pdiv_ate;
340 
341 
342 	temp_a = div64_s64_precise((int64_t) delta_temp * (1LL << 13) * mult,
343 				   (int64_t) delta_sens * div);
344 
345 	tmp = (int64_t)actual_tsensor_ft * shared->actual_temp_cp -
346 	      (int64_t)actual_tsensor_cp * shared->actual_temp_ft;
347 	temp_b = div64_s64_precise(tmp, (int64_t)delta_sens);
348 
349 	temp_a = div64_s64_precise((int64_t)temp_a * sensor->fuse_corr_alpha,
350 				   1000000);
351 	temp_b = div64_s64_precise((int64_t)temp_b * sensor->fuse_corr_alpha +
352 				   sensor->fuse_corr_beta, 1000000);
353 	sensor->therm_a = (int16_t)temp_a;
354 	sensor->therm_b = (int16_t)temp_b;
355 #ifdef DEBUG
356 	printf("%s: sensor %s fuse: 0x%08X (0x%04X, 0x%04X)"
357 	    " calib_cp: %d(0x%04X), calib_ft: %d(0x%04X)\n",
358 	    __func__, sensor->name, val, val & 0x1FFF, (val >> 13) & 0x1FFF,
359 	    calib_cp, calib_cp, calib_ft, calib_ft);
360 	printf("therma: 0x%04X(%d), thermb: 0x%04X(%d)\n",
361 	    (uint16_t)sensor->therm_a, temp_a,
362 	    (uint16_t)sensor->therm_b, sensor->therm_b);
363 #endif
364 }
365 
366 static void
367 soctherm_init_tsensor(struct soctherm_softc *sc, struct tsensor *sensor,
368     struct soctherm_shared_cal *shared_cal)
369 {
370 	uint32_t val;
371 
372 	tsensor_calibration(sensor, shared_cal);
373 
374 	val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
375 	val |= TSENSOR_CONFIG0_STOP;
376 	val |= TSENSOR_CONFIG0_STATUS_CLR;
377 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
378 
379 	val = TSENSOR_CONFIG0_TALL(sensor->cfg->tall);
380 	val |= TSENSOR_CONFIG0_STOP;
381 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
382 
383 	val = TSENSOR_CONFIG1_TSAMPLE(sensor->cfg->tsample - 1);
384 	val |= TSENSOR_CONFIG1_TIDDQ_EN(sensor->cfg->tiddq_en);
385 	val |= TSENSOR_CONFIG1_TEN_COUNT(sensor->cfg->ten_count);
386 	val |= TSENSOR_CONFIG1_TEMP_ENABLE;
387 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG1, val);
388 
389 	val = TSENSOR_CONFIG2_THERMA((uint16_t)sensor->therm_a) |
390 	     TSENSOR_CONFIG2_THERMB((uint16_t)sensor->therm_b);
391 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG2, val);
392 
393 	val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
394 	val &= ~TSENSOR_CONFIG0_STOP;
395 	WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
396 #ifdef DEBUG
397 	printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
398 	    " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
399 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
400 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
401 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
402 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
403 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
404 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
405 	    );
406 #endif
407 }
408 
409 static int
410 soctherm_convert_raw(uint32_t val)
411 {
412 	int32_t t;
413 
414 	t = ((val & READBACK_VALUE_MASK) >> READBACK_VALUE_SHIFT) * 1000;
415 	if (val & READBACK_ADD_HALF)
416 		t += 500;
417 	if (val & READBACK_NEGATE)
418 		t *= -1;
419 
420 	return t;
421 }
422 
423 static int
424 soctherm_read_temp(struct soctherm_softc *sc, struct tsensor *sensor, int *temp)
425 {
426 	int timeout;
427 	uint32_t val;
428 
429 
430 	/* wait for valid sample */
431 	for (timeout = 1000; timeout > 0; timeout--) {
432 		val = RD4(sc, sensor->sensor_base + TSENSOR_STATUS1);
433 		if ((val & TSENSOR_STATUS1_TEMP_VALID) != 0)
434 			break;
435 		DELAY(100);
436 	}
437 	if (timeout <= 0)
438 		device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
439 	*temp = soctherm_convert_raw(val);
440 #ifdef DEBUG
441 	printf("%s: Raw: 0x%08X, temp: %d\n", __func__, val, *temp);
442 	printf(" Sensor: %s  cfg:0x%08X, 0x%08X, 0x%08X,"
443 	    " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
444 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
445 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
446 	    RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
447 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
448 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
449 	    RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
450 	    );
451 #endif
452 	return 0;
453 }
454 
455 static int
456 soctherm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
457 {
458 	struct soctherm_softc *sc;
459 	int i;
460 
461 	sc = device_get_softc(dev);
462 	/* The direct sensor map starts at 0x100 */
463 	if (id >= 0x100) {
464 		id -= 0x100;
465 		if (id >= sc->ntsensors)
466 			return (ERANGE);
467 		return(soctherm_read_temp(sc, sc->tsensors + id, val));
468 	}
469 	/* Linux (DT) compatible thermal zones */
470 	for (i = 0; i < sc->ntsensors; i++) {
471 		if (sc->tsensors->id == id)
472 			return(soctherm_read_temp(sc, sc->tsensors + id, val));
473 	}
474 	return (ERANGE);
475 }
476 
477 static int
478 soctherm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
479 {
480 	struct soctherm_softc *sc;
481 	int val;
482 	int rv;
483 	int id;
484 
485 	/* Write request */
486 	if (req->newptr != NULL)
487 		return (EINVAL);
488 
489 	sc = arg1;
490 	id = arg2;
491 
492 	if (id >= sc->ntsensors)
493 		return (ERANGE);
494 	rv =  soctherm_read_temp(sc, sc->tsensors + id, &val);
495 	if (rv != 0)
496 		return (rv);
497 
498 	val = val / 100;
499 	val +=  2731;
500 	rv = sysctl_handle_int(oidp, &val, 0, req);
501 	return (rv);
502 }
503 
504 static int
505 soctherm_init_sysctl(struct soctherm_softc *sc)
506 {
507 	int i;
508 	struct sysctl_oid *oid, *tmp;
509 
510 	sysctl_ctx_init(&soctherm_sysctl_ctx);
511 	/* create node for hw.temp */
512 	oid = SYSCTL_ADD_NODE(&soctherm_sysctl_ctx,
513 	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
514 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
515 	if (oid == NULL)
516 		return (ENXIO);
517 
518 	/* Add sensors */
519 	for (i = sc->ntsensors  - 1; i >= 0; i--) {
520 		tmp = SYSCTL_ADD_PROC(&soctherm_sysctl_ctx,
521 		    SYSCTL_CHILDREN(oid), OID_AUTO, sc->tsensors[i].name,
522 		    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, i,
523 		    soctherm_sysctl_temperature, "IK", "SoC Temperature");
524 		if (tmp == NULL)
525 			return (ENXIO);
526 	}
527 
528 	return (0);
529 }
530 
531 static int
532 soctherm_probe(device_t dev)
533 {
534 
535 	if (!ofw_bus_status_okay(dev))
536 		return (ENXIO);
537 
538 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
539 		return (ENXIO);
540 
541 	device_set_desc(dev, "Tegra temperature sensors");
542 	return (BUS_PROBE_DEFAULT);
543 }
544 
545 static int
546 soctherm_attach(device_t dev)
547 {
548 	struct soctherm_softc *sc;
549 	phandle_t node;
550 	int i, rid, rv;
551 	struct soctherm_shared_cal shared_calib;
552 
553 	sc = device_get_softc(dev);
554 	sc->dev = dev;
555 	node = ofw_bus_get_node(sc->dev);
556 
557 	rid = 0;
558 	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
559 	    RF_ACTIVE);
560 	if (sc->mem_res == NULL) {
561 		device_printf(dev, "Cannot allocate memory resources\n");
562 		goto fail;
563 	}
564 
565 	rid = 0;
566 	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
567 	if (sc->irq_res == NULL) {
568 		device_printf(dev, "Cannot allocate IRQ resources\n");
569 		goto fail;
570 	}
571 
572 /*
573 	if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
574 	    soctherm_intr, NULL, sc, &sc->irq_ih))) {
575 		device_printf(dev,
576 		    "WARNING: unable to register interrupt handler\n");
577 		goto fail;
578 	}
579 */
580 
581 	/* OWF resources */
582 	rv = hwreset_get_by_ofw_name(dev, 0, "soctherm", &sc->reset);
583 	if (rv != 0) {
584 		device_printf(dev, "Cannot get fuse reset\n");
585 		goto fail;
586 	}
587 	rv = clk_get_by_ofw_name(dev, 0, "tsensor", &sc->tsensor_clk);
588 	if (rv != 0) {
589 		device_printf(dev, "Cannot get 'tsensor' clock: %d\n", rv);
590 		goto fail;
591 	}
592 	rv = clk_get_by_ofw_name(dev, 0, "soctherm", &sc->soctherm_clk);
593 	if (rv != 0) {
594 		device_printf(dev, "Cannot get 'soctherm' clock: %d\n", rv);
595 		goto fail;
596 	}
597 
598 	rv = hwreset_assert(sc->reset);
599 	if (rv != 0) {
600 		device_printf(dev, "Cannot assert reset\n");
601 		goto fail;
602 	}
603 	rv = clk_enable(sc->tsensor_clk);
604 	if (rv != 0) {
605 		device_printf(dev, "Cannot enable 'tsensor' clock: %d\n", rv);
606 		goto fail;
607 	}
608 	rv = clk_enable(sc->soctherm_clk);
609 	if (rv != 0) {
610 		device_printf(dev, "Cannot enable 'soctherm' clock: %d\n", rv);
611 		goto fail;
612 	}
613 	rv = hwreset_deassert(sc->reset);
614 	if (rv != 0) {
615 		device_printf(dev, "Cannot clear reset\n");
616 		goto fail;
617 	}
618 
619 	/* Tegra 124 */
620 	sc->tsensors = t124_tsensors;
621 	sc->ntsensors = nitems(t124_tsensors);
622 	get_shared_cal(sc, &shared_calib);
623 
624 	WR4(sc, TSENSOR_PDIV, TSENSOR_PDIV_T124);
625 	WR4(sc, TSENSOR_HOTSPOT_OFF, TSENSOR_HOTSPOT_OFF_T124);
626 
627 	for (i = 0; i < sc->ntsensors; i++)
628 		soctherm_init_tsensor(sc, sc->tsensors + i, &shared_calib);
629 
630 	rv = soctherm_init_sysctl(sc);
631 	if (rv != 0) {
632 		device_printf(sc->dev, "Cannot initialize sysctls\n");
633 		goto fail;
634 	}
635 
636 	OF_device_register_xref(OF_xref_from_node(node), dev);
637 	return (bus_generic_attach(dev));
638 
639 fail:
640 	if (sc->irq_ih != NULL)
641 		bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
642 	sysctl_ctx_free(&soctherm_sysctl_ctx);
643 	if (sc->tsensor_clk != NULL)
644 		clk_release(sc->tsensor_clk);
645 	if (sc->soctherm_clk != NULL)
646 		clk_release(sc->soctherm_clk);
647 	if (sc->reset != NULL)
648 		hwreset_release(sc->reset);
649 	if (sc->irq_res != NULL)
650 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
651 	if (sc->mem_res != NULL)
652 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
653 
654 	return (ENXIO);
655 }
656 
657 static int
658 soctherm_detach(device_t dev)
659 {
660 	struct soctherm_softc *sc;
661 	sc = device_get_softc(dev);
662 
663 	if (sc->irq_ih != NULL)
664 		bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
665 	sysctl_ctx_free(&soctherm_sysctl_ctx);
666 	if (sc->tsensor_clk != NULL)
667 		clk_release(sc->tsensor_clk);
668 	if (sc->soctherm_clk != NULL)
669 		clk_release(sc->soctherm_clk);
670 	if (sc->reset != NULL)
671 		hwreset_release(sc->reset);
672 	if (sc->irq_res != NULL)
673 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
674 	if (sc->mem_res != NULL)
675 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
676 
677 	return (ENXIO);
678 }
679 
680 static device_method_t tegra_soctherm_methods[] = {
681 	/* Device interface */
682 	DEVMETHOD(device_probe,			soctherm_probe),
683 	DEVMETHOD(device_attach,		soctherm_attach),
684 	DEVMETHOD(device_detach,		soctherm_detach),
685 
686 	/* SOCTHERM interface */
687 	DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
688 
689 	DEVMETHOD_END
690 };
691 
692 static devclass_t tegra_soctherm_devclass;
693 static DEFINE_CLASS_0(soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
694     sizeof(struct soctherm_softc));
695 EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,
696     tegra_soctherm_devclass, NULL, NULL, 79);
697