2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
29 * Thermometer and thermal zones driver for Tegra SoCs.
30 * Calibration data and algo are taken from Linux, because this part of SoC
31 * is undocumented in TRM.
34 #include <sys/param.h>
35 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/malloc.h>
42 #include <sys/sysctl.h>
44 #include <machine/bus.h>
46 #include <dev/extres/clk/clk.h>
47 #include <dev/extres/hwreset/hwreset.h>
48 #include <dev/ofw/ofw_bus.h>
49 #include <dev/ofw/ofw_bus_subr.h>
51 #include <arm/nvidia/tegra_efuse.h>
52 #include <dt-bindings/thermal/tegra124-soctherm.h>
53 #include "tegra_soctherm_if.h"
55 /* Per sensors registers - base is 0x0c0*/
56 #define TSENSOR_CONFIG0 0x000
57 #define TSENSOR_CONFIG0_TALL(x) (((x) & 0xFFFFF) << 8)
58 #define TSENSOR_CONFIG0_STATUS_CLR (1 << 5)
59 #define TSENSOR_CONFIG0_TCALC_OVERFLOW (1 << 4)
60 #define TSENSOR_CONFIG0_OVERFLOW (1 << 3)
61 #define TSENSOR_CONFIG0_CPTR_OVERFLOW (1 << 2)
62 #define TSENSOR_CONFIG0_RO_SEL (1 << 1)
63 #define TSENSOR_CONFIG0_STOP (1 << 0)
65 #define TSENSOR_CONFIG1 0x004
66 #define TSENSOR_CONFIG1_TEMP_ENABLE (1U << 31)
67 #define TSENSOR_CONFIG1_TEN_COUNT(x) (((x) & 0x3F) << 24)
68 #define TSENSOR_CONFIG1_TIDDQ_EN(x) (((x) & 0x3F) << 15)
69 #define TSENSOR_CONFIG1_TSAMPLE(x) (((x) & 0x3FF) << 0)
71 #define TSENSOR_CONFIG2 0x008
72 #define TSENSOR_CONFIG2_THERMA(x) (((x) & 0xFFFF) << 16)
73 #define TSENSOR_CONFIG2_THERMB(x) (((x) & 0xFFFF) << 0)
75 #define TSENSOR_STATUS0 0x00c
76 #define TSENSOR_STATUS0_CAPTURE_VALID (1U << 31)
77 #define TSENSOR_STATUS0_CAPTURE(x) (((x) >> 0) & 0xffff)
79 #define TSENSOR_STATUS1 0x010
80 #define TSENSOR_STATUS1_TEMP_VALID (1U << 31)
81 #define TSENSOR_STATUS1_TEMP(x) (((x) >> 0) & 0xffff)
83 #define TSENSOR_STATUS2 0x014
84 #define TSENSOR_STATUS2_TEMP_MAX(x) (((x) >> 16) & 0xffff)
85 #define TSENSOR_STATUS2_TEMP_MIN(x) (((x) >> 0) & 0xffff)
89 #define READBACK_VALUE(x) (((x) >> 8) & 0xff)
90 #define READBACK_ADD_HALF (1 << 7)
91 #define READBACK_NEGATE (1 << 0)
93 /* Global registers */
94 #define TSENSOR_PDIV 0x1c0
95 #define TSENSOR_HOTSPOT_OFF 0x1c4
96 #define TSENSOR_TEMP1 0x1c8
97 #define TSENSOR_TEMP2 0x1cc
100 #define FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT 0
101 #define FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS 13
102 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT 13
103 #define FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS 13
105 /* Layout is different for Tegra124 and Tegra210 */
106 #define FUSE_TSENSOR_COMMON 0x180
107 #define TEGRA124_FUSE_COMMON_CP_TS_BASE(x) (((x) >> 0) & 0x3ff)
108 #define TEGRA124_FUSE_COMMON_FT_TS_BASE(x) (((x) >> 10) & 0x7ff)
109 #define TEGRA124_FUSE_COMMON_SHIFT_FT_SHIFT 21
110 #define TEGRA124_FUSE_COMMON_SHIFT_FT_BITS 5
112 #define TEGRA210_FUSE_COMMON_CP_TS_BASE(x) (((x) >> 11) & 0x3ff)
113 #define TEGRA210_FUSE_COMMON_FT_TS_BASE(x) (((x) >> 21) & 0x7ff)
114 #define TEGRA210_FUSE_COMMON_SHIFT_CP_SHIFT 0
115 #define TEGRA210_FUSE_COMMON_SHIFT_CP_BITS 6
116 #define TEGRA210_FUSE_COMMON_SHIFT_FT_SHIFT 6
117 #define TEGRA210_FUSE_COMMON_SHIFT_FT_BITS 5
120 /* Only for Tegra124 */
121 #define FUSE_SPARE_REALIGNMENT_REG 0x1fc
122 #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT 0
123 #define FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS 6
125 #define TEGRA124_NOMINAL_CALIB_FT 105
126 #define TEGRA124_NOMINAL_CALIB_CP 25
128 #define TEGRA210_NOMINAL_CALIB_FT 105
129 #define TEGRA210_NOMINAL_CALIB_CP 25
131 #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
132 #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
134 static struct sysctl_ctx_list soctherm_sysctl_ctx;
142 uint32_t tsample_ate;
146 struct soctherm_shared_cal {
149 int32_t actual_temp_cp;
150 int32_t actual_temp_ft;
156 bus_addr_t sensor_base;
157 bus_addr_t calib_fuse;
166 struct soctherm_softc {
168 struct resource *mem_res;
169 struct resource *irq_res;
176 struct soctherm_soc *soc;
177 struct soctherm_shared_cal shared_cal;
180 struct soctherm_soc {
181 void (*shared_cal)(struct soctherm_softc *sc);
182 uint32_t tsensor_pdiv;
183 uint32_t tsensor_hotspot_off;
184 struct tsensor_cfg *tsensor_cfg;
185 struct tsensor *tsensors;
189 /* Tegra124 config */
191 static struct tsensor_cfg t124_tsensor_config = {
201 static struct tsensor t124_tsensors[] = {
204 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
205 .sensor_base = 0x0c0,
207 .fuse_corr_alpha = 1135400,
208 .fuse_corr_beta = -6266900,
213 .sensor_base = 0x0e0,
215 .fuse_corr_alpha = 1122220,
216 .fuse_corr_beta = -5700700,
221 .sensor_base = 0x100,
223 .fuse_corr_alpha = 1127000,
224 .fuse_corr_beta = -6768200,
229 .sensor_base = 0x120,
231 .fuse_corr_alpha = 1110900,
232 .fuse_corr_beta = -6232000,
236 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
237 .sensor_base = 0x140,
239 .fuse_corr_alpha = 1122300,
240 .fuse_corr_beta = -5936400,
245 .sensor_base = 0x160,
247 .fuse_corr_alpha = 1145700,
248 .fuse_corr_beta = -7124600,
252 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
253 .sensor_base = 0x180,
255 .fuse_corr_alpha = 1120100,
256 .fuse_corr_beta = -6000500,
260 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
261 .sensor_base = 0x1a0,
263 .fuse_corr_alpha = 1106500,
264 .fuse_corr_beta = -6729300,
268 static void tegra124_shared_cal(struct soctherm_softc *sc);
270 static struct soctherm_soc tegra124_soc = {
271 .shared_cal = tegra124_shared_cal,
272 .tsensor_pdiv = 0x8888,
273 .tsensor_hotspot_off = 0x00060600 ,
274 .tsensor_cfg = &t124_tsensor_config,
275 .tsensors = t124_tsensors,
276 .ntsensors = nitems(t124_tsensors),
279 /* Tegra210 config */
280 static struct tsensor_cfg t210_tsensor_config = {
290 static struct tsensor t210_tsensors[] = {
293 .id = TEGRA124_SOCTHERM_SENSOR_CPU,
294 .sensor_base = 0x0c0,
296 .fuse_corr_alpha = 1085000,
297 .fuse_corr_beta = 3244200,
302 .sensor_base = 0x0e0,
304 .fuse_corr_alpha = 1126200,
305 .fuse_corr_beta = -67500,
310 .sensor_base = 0x100,
312 .fuse_corr_alpha = 1098400,
313 .fuse_corr_beta = 2251100,
318 .sensor_base = 0x120,
320 .fuse_corr_alpha = 1108000,
321 .fuse_corr_beta = 602700,
325 .id = TEGRA124_SOCTHERM_SENSOR_MEM,
326 .sensor_base = 0x140,
328 .fuse_corr_alpha = 1069200,
329 .fuse_corr_beta = 3549900,
334 .sensor_base = 0x160,
336 .fuse_corr_alpha = 1173700,
337 .fuse_corr_beta = -6263600,
341 .id = TEGRA124_SOCTHERM_SENSOR_GPU,
342 .sensor_base = 0x180,
344 .fuse_corr_alpha = 1074300,
345 .fuse_corr_beta = 2734900,
349 .id = TEGRA124_SOCTHERM_SENSOR_PLLX,
350 .sensor_base = 0x1a0,
352 .fuse_corr_alpha = 1039700,
353 .fuse_corr_beta = 6829100,
357 static void tegra210_shared_cal(struct soctherm_softc *sc);
359 static struct soctherm_soc tegra210_soc = {
360 .shared_cal = tegra210_shared_cal,
361 .tsensor_pdiv = 0x8888,
362 .tsensor_hotspot_off = 0x000A0500 ,
363 .tsensor_cfg = &t210_tsensor_config,
364 .tsensors = t210_tsensors,
365 .ntsensors = nitems(t210_tsensors),
368 static struct ofw_compat_data compat_data[] = {
369 {"nvidia,tegra124-soctherm", (uintptr_t)&tegra124_soc},
370 {"nvidia,tegra210-soctherm", (uintptr_t)&tegra210_soc},
374 /* Extract signed integer bitfield from register */
376 extract_signed(uint32_t reg, int shift, int bits)
381 mask = (1 << bits) - 1;
382 val = ((reg >> shift) & mask) << (32 - bits);
384 return ((int32_t)val);
388 int64_t div64_s64_precise(int64_t a, int64_t b)
393 r = (al * 2 + 1) / (2 * b);
398 tegra124_shared_cal(struct soctherm_softc *sc)
401 int calib_cp, calib_ft;
402 struct soctherm_shared_cal *cal;
404 cal = &sc->shared_cal;
405 val = tegra_fuse_read_4(FUSE_TSENSOR_COMMON);
406 cal->base_cp = TEGRA124_FUSE_COMMON_CP_TS_BASE(val);
407 cal->base_ft = TEGRA124_FUSE_COMMON_FT_TS_BASE(val);
409 calib_ft = extract_signed(val,
410 TEGRA124_FUSE_COMMON_SHIFT_FT_SHIFT,
411 TEGRA124_FUSE_COMMON_SHIFT_FT_BITS);
413 val = tegra_fuse_read_4(FUSE_SPARE_REALIGNMENT_REG);
414 calib_cp = extract_signed(val,
415 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_SHIFT,
416 FUSE_SPARE_REALIGNMENT_REG_SHIFT_CP_BITS);
418 cal->actual_temp_cp = 2 * TEGRA124_NOMINAL_CALIB_CP + calib_cp;
419 cal->actual_temp_ft = 2 * TEGRA124_NOMINAL_CALIB_FT + calib_ft;
421 printf("%s: base_cp: %u, base_ft: %d,"
422 " actual_temp_cp: %d, actual_temp_ft: %d\n",
423 __func__, cal->base_cp, cal->base_ft,
424 cal->actual_temp_cp, cal->actual_temp_ft);
429 tegra210_shared_cal(struct soctherm_softc *sc)
432 int calib_cp, calib_ft;
433 struct soctherm_shared_cal *cal;
435 cal = &sc->shared_cal;
437 val = tegra_fuse_read_4(FUSE_TSENSOR_COMMON);
438 cal->base_cp = TEGRA210_FUSE_COMMON_CP_TS_BASE(val);
439 cal->base_ft = TEGRA210_FUSE_COMMON_FT_TS_BASE(val);
441 calib_ft = extract_signed(val,
442 TEGRA210_FUSE_COMMON_SHIFT_FT_SHIFT,
443 TEGRA210_FUSE_COMMON_SHIFT_FT_BITS);
444 calib_cp = extract_signed(val,
445 TEGRA210_FUSE_COMMON_SHIFT_CP_SHIFT,
446 TEGRA210_FUSE_COMMON_SHIFT_CP_BITS);
448 cal->actual_temp_cp = 2 * TEGRA210_NOMINAL_CALIB_CP + calib_cp;
449 cal->actual_temp_ft = 2 * TEGRA210_NOMINAL_CALIB_FT + calib_ft;
451 printf("%s: base_cp: %u, base_ft: %d,"
452 " actual_temp_cp: %d, actual_temp_ft: %d\n",
453 __func__, cal->base_cp, cal->base_ft,
454 cal->actual_temp_cp, cal->actual_temp_ft);
459 tsensor_calibration(struct soctherm_softc *sc, struct tsensor *sensor)
462 int mult, div, calib_cp, calib_ft;
463 int actual_tsensor_ft, actual_tsensor_cp, delta_sens, delta_temp;
465 struct tsensor_cfg *cfg;
466 struct soctherm_shared_cal *cal;
469 cfg = sc->soc->tsensor_cfg;
470 cal = &sc->shared_cal;
472 val = tegra_fuse_read_4(sensor->calib_fuse);
473 calib_cp = extract_signed(val,
474 FUSE_TSENSOR_CALIB_CP_TS_BASE_SHIFT,
475 FUSE_TSENSOR_CALIB_CP_TS_BASE_BITS);
476 actual_tsensor_cp = cal->base_cp * 64 + calib_cp;
478 calib_ft = extract_signed(val,
479 FUSE_TSENSOR_CALIB_FT_TS_BASE_SHIFT,
480 FUSE_TSENSOR_CALIB_FT_TS_BASE_BITS);
481 actual_tsensor_ft = cal->base_ft * 32 + calib_ft;
483 delta_sens = actual_tsensor_ft - actual_tsensor_cp;
484 delta_temp = cal->actual_temp_ft - cal->actual_temp_cp;
485 mult = cfg->pdiv * cfg->tsample_ate;
486 div = cfg->tsample * cfg->pdiv_ate;
488 temp_a = div64_s64_precise((int64_t) delta_temp * (1LL << 13) * mult,
489 (int64_t) delta_sens * div);
491 tmp = (int64_t)actual_tsensor_ft * cal->actual_temp_cp -
492 (int64_t)actual_tsensor_cp * cal->actual_temp_ft;
493 temp_b = div64_s64_precise(tmp, (int64_t)delta_sens);
495 temp_a = div64_s64_precise((int64_t)temp_a * sensor->fuse_corr_alpha,
497 temp_b = div64_s64_precise((int64_t)temp_b * sensor->fuse_corr_alpha +
498 sensor->fuse_corr_beta, 1000000);
499 sensor->therm_a = (int16_t)temp_a;
500 sensor->therm_b = (int16_t)temp_b;
502 printf("%s: sensor %s fuse: 0x%08X (0x%04X, 0x%04X)"
503 " calib_cp: %d(0x%04X), calib_ft: %d(0x%04X)\n",
504 __func__, sensor->name, val, val & 0x1FFF, (val >> 13) & 0x1FFF,
505 calib_cp, calib_cp, calib_ft, calib_ft);
506 printf("therma: 0x%04X(%d), thermb: 0x%04X(%d)\n",
507 (uint16_t)sensor->therm_a, sensor->therm_a,
508 (uint16_t)sensor->therm_b, sensor->therm_b);
513 soctherm_init_tsensor(struct soctherm_softc *sc, struct tsensor *sensor)
515 struct tsensor_cfg *cfg;
518 cfg = sc->soc->tsensor_cfg;
519 tsensor_calibration(sc, sensor);
521 val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
522 val |= TSENSOR_CONFIG0_STOP;
523 val |= TSENSOR_CONFIG0_STATUS_CLR;
524 WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
526 val = TSENSOR_CONFIG0_TALL(cfg->tall);
527 val |= TSENSOR_CONFIG0_STOP;
528 WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
530 val = TSENSOR_CONFIG1_TSAMPLE(cfg->tsample - 1);
531 val |= TSENSOR_CONFIG1_TIDDQ_EN(cfg->tiddq_en);
532 val |= TSENSOR_CONFIG1_TEN_COUNT(cfg->ten_count);
533 val |= TSENSOR_CONFIG1_TEMP_ENABLE;
534 WR4(sc, sensor->sensor_base + TSENSOR_CONFIG1, val);
536 val = TSENSOR_CONFIG2_THERMA((uint16_t)sensor->therm_a) |
537 TSENSOR_CONFIG2_THERMB((uint16_t)sensor->therm_b);
538 WR4(sc, sensor->sensor_base + TSENSOR_CONFIG2, val);
540 val = RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0);
541 val &= ~TSENSOR_CONFIG0_STOP;
542 WR4(sc, sensor->sensor_base + TSENSOR_CONFIG0, val);
544 printf(" Sensor: %s cfg:0x%08X, 0x%08X, 0x%08X,"
545 " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
546 RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
547 RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
548 RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
549 RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
550 RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
551 RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
557 soctherm_convert_raw(uint32_t val)
561 t = READBACK_VALUE(val) * 1000;
562 if (val & READBACK_ADD_HALF)
564 if (val & READBACK_NEGATE)
571 soctherm_read_temp(struct soctherm_softc *sc, struct tsensor *sensor, int *temp)
576 /* wait for valid sample */
577 for (timeout = 100; timeout > 0; timeout--) {
578 val = RD4(sc, sensor->sensor_base + TSENSOR_STATUS1);
579 if ((val & TSENSOR_STATUS1_TEMP_VALID) != 0)
584 device_printf(sc->dev, "Sensor %s timeouted\n", sensor->name);
585 *temp = soctherm_convert_raw(val);
587 printf("%s: Raw: 0x%08X, temp: %d\n", __func__, val, *temp);
588 printf(" Sensor: %s cfg:0x%08X, 0x%08X, 0x%08X,"
589 " sts:0x%08X, 0x%08X, 0x%08X\n", sensor->name,
590 RD4(sc, sensor->sensor_base + TSENSOR_CONFIG0),
591 RD4(sc, sensor->sensor_base + TSENSOR_CONFIG1),
592 RD4(sc, sensor->sensor_base + TSENSOR_CONFIG2),
593 RD4(sc, sensor->sensor_base + TSENSOR_STATUS0),
594 RD4(sc, sensor->sensor_base + TSENSOR_STATUS1),
595 RD4(sc, sensor->sensor_base + TSENSOR_STATUS2)
602 soctherm_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
604 struct soctherm_softc *sc;
607 sc = device_get_softc(dev);
608 /* The direct sensor map starts at 0x100 */
611 if (id >= sc->soc->ntsensors)
613 return(soctherm_read_temp(sc, sc->soc->tsensors + id, val));
615 /* Linux (DT) compatible thermal zones */
616 for (i = 0; i < sc->soc->ntsensors; i++) {
617 if (sc->soc->tsensors->id == id) {
618 return(soctherm_read_temp(sc, sc->soc->tsensors + id,
626 soctherm_sysctl_temperature(SYSCTL_HANDLER_ARGS)
628 struct soctherm_softc *sc;
634 if (req->newptr != NULL)
640 if (id >= sc->soc->ntsensors)
642 rv = soctherm_read_temp(sc, sc->soc->tsensors + id, &val);
648 rv = sysctl_handle_int(oidp, &val, 0, req);
653 soctherm_init_sysctl(struct soctherm_softc *sc)
656 struct sysctl_oid *oid, *tmp;
658 sysctl_ctx_init(&soctherm_sysctl_ctx);
659 /* create node for hw.temp */
660 oid = SYSCTL_ADD_NODE(&soctherm_sysctl_ctx,
661 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
662 CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "");
667 for (i = sc->soc->ntsensors - 1; i >= 0; i--) {
668 tmp = SYSCTL_ADD_PROC(&soctherm_sysctl_ctx,
669 SYSCTL_CHILDREN(oid), OID_AUTO, sc->soc->tsensors[i].name,
670 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, i,
671 soctherm_sysctl_temperature, "IK", "SoC Temperature");
680 soctherm_probe(device_t dev)
683 if (!ofw_bus_status_okay(dev))
686 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
689 device_set_desc(dev, "Tegra temperature sensors");
690 return (BUS_PROBE_DEFAULT);
694 soctherm_attach(device_t dev)
696 struct soctherm_softc *sc;
700 sc = device_get_softc(dev);
702 sc->soc = (struct soctherm_soc *)ofw_bus_search_compatible(dev,
703 compat_data)->ocd_data;
704 node = ofw_bus_get_node(sc->dev);
707 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
709 if (sc->mem_res == NULL) {
710 device_printf(dev, "Cannot allocate memory resources\n");
715 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
716 if (sc->irq_res == NULL) {
717 device_printf(dev, "Cannot allocate IRQ resources\n");
722 if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC,
723 soctherm_intr, NULL, sc, &sc->irq_ih))) {
725 "WARNING: unable to register interrupt handler\n");
731 rv = hwreset_get_by_ofw_name(dev, 0, "soctherm", &sc->reset);
733 device_printf(dev, "Cannot get fuse reset\n");
736 rv = clk_get_by_ofw_name(dev, 0, "tsensor", &sc->tsensor_clk);
738 device_printf(dev, "Cannot get 'tsensor' clock: %d\n", rv);
741 rv = clk_get_by_ofw_name(dev, 0, "soctherm", &sc->soctherm_clk);
743 device_printf(dev, "Cannot get 'soctherm' clock: %d\n", rv);
747 rv = hwreset_assert(sc->reset);
749 device_printf(dev, "Cannot assert reset\n");
752 rv = clk_enable(sc->tsensor_clk);
754 device_printf(dev, "Cannot enable 'tsensor' clock: %d\n", rv);
757 rv = clk_enable(sc->soctherm_clk);
759 device_printf(dev, "Cannot enable 'soctherm' clock: %d\n", rv);
762 rv = hwreset_deassert(sc->reset);
764 device_printf(dev, "Cannot clear reset\n");
768 sc->soc->shared_cal(sc);
770 WR4(sc, TSENSOR_PDIV, sc->soc->tsensor_pdiv);
771 WR4(sc, TSENSOR_HOTSPOT_OFF, sc->soc->tsensor_hotspot_off);
773 for (i = 0; i < sc->soc->ntsensors; i++)
774 soctherm_init_tsensor(sc, sc->soc->tsensors + i);
776 rv = soctherm_init_sysctl(sc);
778 device_printf(sc->dev, "Cannot initialize sysctls\n");
782 OF_device_register_xref(OF_xref_from_node(node), dev);
783 return (bus_generic_attach(dev));
786 if (sc->irq_ih != NULL)
787 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
788 sysctl_ctx_free(&soctherm_sysctl_ctx);
789 if (sc->tsensor_clk != NULL)
790 clk_release(sc->tsensor_clk);
791 if (sc->soctherm_clk != NULL)
792 clk_release(sc->soctherm_clk);
793 if (sc->reset != NULL)
794 hwreset_release(sc->reset);
795 if (sc->irq_res != NULL)
796 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
797 if (sc->mem_res != NULL)
798 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
804 soctherm_detach(device_t dev)
806 struct soctherm_softc *sc;
807 sc = device_get_softc(dev);
809 if (sc->irq_ih != NULL)
810 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
811 sysctl_ctx_free(&soctherm_sysctl_ctx);
812 if (sc->tsensor_clk != NULL)
813 clk_release(sc->tsensor_clk);
814 if (sc->soctherm_clk != NULL)
815 clk_release(sc->soctherm_clk);
816 if (sc->reset != NULL)
817 hwreset_release(sc->reset);
818 if (sc->irq_res != NULL)
819 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
820 if (sc->mem_res != NULL)
821 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
826 static device_method_t tegra_soctherm_methods[] = {
827 /* Device interface */
828 DEVMETHOD(device_probe, soctherm_probe),
829 DEVMETHOD(device_attach, soctherm_attach),
830 DEVMETHOD(device_detach, soctherm_detach),
832 /* SOCTHERM interface */
833 DEVMETHOD(tegra_soctherm_get_temperature, soctherm_get_temp),
838 static DEFINE_CLASS_0(soctherm, tegra_soctherm_driver, tegra_soctherm_methods,
839 sizeof(struct soctherm_softc));
840 EARLY_DRIVER_MODULE(tegra_soctherm, simplebus, tegra_soctherm_driver,