2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
32 * Thermometer and thermal zones driver for RockChip SoCs.
33 * Calibration data are taken from Linux, because this part of SoC
34 * is undocumented in TRM.
37 #include <sys/param.h>
38 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/malloc.h>
45 #include <sys/sysctl.h>
47 #include <machine/bus.h>
49 #include <dev/extres/clk/clk.h>
50 #include <dev/extres/hwreset/hwreset.h>
51 #include <dev/extres/syscon/syscon.h>
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
55 #include "syscon_if.h"
56 #include "rk_tsadc_if.h"
58 /* Global registers */
59 #define TSADC_USER_CON 0x000
60 #define TSADC_AUTO_CON 0x004
61 #define TSADC_AUTO_CON_POL_HI (1 << 8)
62 #define TSADC_AUTO_SRC_EN(x) (1 << (4 + (x)))
63 #define TSADC_AUTO_Q_SEL (1 << 1) /* V3 only */
64 #define TSADC_AUTO_CON_AUTO (1 << 0)
66 #define TSADC_INT_EN 0x008
67 #define TSADC_INT_EN_2CRU_EN_SRC(x) (1 << (8 + (x)))
68 #define TSADC_INT_EN_2GPIO_EN_SRC(x) (1 << (4 + (x)))
69 #define TSADC_INT_PD 0x00c
70 #define TSADC_DATA(x) (0x20 + (x) * 0x04)
71 #define TSADC_COMP_INT(x) (0x30 + (x) * 0x04)
72 #define TSADC_COMP_INT_SRC_EN(x) (1 << (0 + (x)))
73 #define TSADC_COMP_SHUT(x) (0x40 + (x) * 0x04)
74 #define TSADC_HIGHT_INT_DEBOUNCE 0x060
75 #define TSADC_HIGHT_TSHUT_DEBOUNCE 0x064
76 #define TSADC_AUTO_PERIOD 0x068
77 #define TSADC_AUTO_PERIOD_HT 0x06c
78 #define TSADC_COMP0_LOW_INT 0x080 /* V3 only */
79 #define TSADC_COMP1_LOW_INT 0x084 /* V3 only */
82 #define GRF_SARADC_TESTBIT 0x0e644
83 #define GRF_SARADC_TESTBIT_ON (0x10001 << 2)
84 #define GRF_TSADC_TESTBIT_L 0x0e648
85 #define GRF_TSADC_VCM_EN_L (0x10001 << 7)
86 #define GRF_TSADC_TESTBIT_H 0x0e64c
87 #define GRF_TSADC_VCM_EN_H (0x10001 << 7)
88 #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2)
90 #define WR4(_sc, _r, _v) bus_write_4((_sc)->mem_res, (_r), (_v))
91 #define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
93 static struct sysctl_ctx_list tsadc_sysctl_ctx;
106 struct rk_calib_entry {
111 struct tsadc_calib_info {
113 struct rk_calib_entry *table;
118 enum tsadc_type type;
122 struct tsensor *tsensors;
124 struct tsadc_calib_info calib_info;
129 struct resource *mem_res;
130 struct resource *irq_res;
138 struct tsadc_conf *conf;
147 static struct rk_calib_entry rk3288_calib_data[] = {
184 struct tsensor rk3288_tsensors[] = {
185 { .channel = 0, .id = 2, .name = "reserved"},
186 { .channel = 1, .id = 0, .name = "CPU"},
187 { .channel = 2, .id = 1, .name = "GPU"},
190 struct tsadc_conf rk3288_tsadc_conf = {
192 .shutdown_temp = 95000,
193 .shutdown_mode = 1, /* GPIO */
194 .shutdown_pol = 0, /* Low */
195 .tsensors = rk3288_tsensors,
196 .ntsensors = nitems(rk3288_tsensors),
198 .table = rk3288_calib_data,
199 .nentries = nitems(rk3288_calib_data),
203 static struct rk_calib_entry rk3328_calib_data[] = {
239 static struct tsensor rk3328_tsensors[] = {
240 { .channel = 0, .id = 0, .name = "CPU"},
243 static struct tsadc_conf rk3328_tsadc_conf = {
245 .shutdown_temp = 95000,
246 .shutdown_mode = 0, /* CRU */
247 .shutdown_pol = 0, /* Low */
248 .tsensors = rk3328_tsensors,
249 .ntsensors = nitems(rk3328_tsensors),
251 .table = rk3328_calib_data,
252 .nentries = nitems(rk3328_calib_data),
256 static struct rk_calib_entry rk3399_calib_data[] = {
293 static struct tsensor rk3399_tsensors[] = {
294 { .channel = 0, .id = 0, .name = "CPU"},
295 { .channel = 1, .id = 1, .name = "GPU"},
298 static struct tsadc_conf rk3399_tsadc_conf = {
300 .shutdown_temp = 95000,
301 .shutdown_mode = 1, /* GPIO */
302 .shutdown_pol = 0, /* Low */
303 .tsensors = rk3399_tsensors,
304 .ntsensors = nitems(rk3399_tsensors),
306 .table = rk3399_calib_data,
307 .nentries = nitems(rk3399_calib_data),
311 static struct ofw_compat_data compat_data[] = {
312 {"rockchip,rk3288-tsadc", (uintptr_t)&rk3288_tsadc_conf},
313 {"rockchip,rk3328-tsadc", (uintptr_t)&rk3328_tsadc_conf},
314 {"rockchip,rk3399-tsadc", (uintptr_t)&rk3399_tsadc_conf},
319 tsadc_temp_to_raw(struct tsadc_softc *sc, int temp)
321 struct rk_calib_entry *tbl;
322 int denom, ntbl, raw, i;
324 tbl = sc->conf->calib_info.table;
325 ntbl = sc->conf->calib_info.nentries;
327 if (temp <= tbl[0].temp)
330 if (temp >= tbl[ntbl - 1].temp)
331 return (tbl[ntbl - 1].raw);
333 for (i = 1; i < (ntbl - 1); i++) {
335 if (temp == tbl[i].temp)
337 if (temp < tbl[i].temp)
342 * Translated value is between i and i - 1 table entries.
343 * Do linear interpolation for it.
345 raw = (int)tbl[i - 1].raw - (int)tbl[i].raw;
346 raw *= temp - tbl[i - 1].temp;
347 denom = tbl[i - 1].temp - tbl[i].temp;
348 raw = tbl[i - 1].raw + raw / denom;
353 tsadc_raw_to_temp(struct tsadc_softc *sc, uint32_t raw)
355 struct rk_calib_entry *tbl;
356 int denom, ntbl, temp, i;
359 tbl = sc->conf->calib_info.table;
360 ntbl = sc->conf->calib_info.nentries;
361 descending = tbl[0].raw > tbl[1].raw;
364 /* Raw column is in descending order. */
365 if (raw >= tbl[0].raw)
366 return (tbl[0].temp);
367 if (raw <= tbl[ntbl - 1].raw)
368 return (tbl[ntbl - 1].temp);
370 for (i = ntbl - 2; i > 0; i--) {
372 if (raw == tbl[i].raw)
373 return (tbl[i].temp);
374 if (raw < tbl[i].raw)
378 /* Raw column is in ascending order. */
379 if (raw <= tbl[0].raw)
380 return (tbl[0].temp);
381 if (raw >= tbl[ntbl - 1].raw)
382 return (tbl[ntbl - 1].temp);
383 for (i = 1; i < (ntbl - 1); i++) {
385 if (raw == tbl[i].raw)
386 return (tbl[i].temp);
387 if (raw < tbl[i].raw)
394 * Translated value is between i and i - 1 table entries.
395 * Do linear interpolation for it.
397 temp = (int)tbl[i - 1].temp - (int)tbl[i].temp;
398 temp *= raw - tbl[i - 1].raw;
399 denom = tbl[i - 1].raw - tbl[i].raw;
400 temp = tbl[i - 1].temp + temp / denom;
405 tsadc_init_tsensor(struct tsadc_softc *sc, struct tsensor *sensor)
410 val = RD4(sc, TSADC_INT_EN);
411 if (sc->shutdown_mode != 0) {
412 /* Signal shutdown of GPIO pin */
413 val &= ~TSADC_INT_EN_2CRU_EN_SRC(sensor->channel);
414 val |= TSADC_INT_EN_2GPIO_EN_SRC(sensor->channel);
416 val |= TSADC_INT_EN_2CRU_EN_SRC(sensor->channel);
417 val &= ~TSADC_INT_EN_2GPIO_EN_SRC(sensor->channel);
419 WR4(sc, TSADC_INT_EN, val);
421 /* Shutdown temperature */
422 val = tsadc_raw_to_temp(sc, sc->shutdown_temp);
423 WR4(sc, TSADC_COMP_SHUT(sensor->channel), val);
424 val = RD4(sc, TSADC_AUTO_CON);
425 val |= TSADC_AUTO_SRC_EN(sensor->channel);
426 WR4(sc, TSADC_AUTO_CON, val);
428 /* Alarm temperature */
429 val = tsadc_temp_to_raw(sc, sc->alarm_temp);
430 WR4(sc, TSADC_COMP_INT(sensor->channel), val);
431 val = RD4(sc, TSADC_INT_EN);
432 val |= TSADC_COMP_INT_SRC_EN(sensor->channel);
433 WR4(sc, TSADC_INT_EN, val);
437 tsadc_init(struct tsadc_softc *sc)
442 val = 0; /* XXX Is this right? */
443 if (sc->shutdown_pol != 0)
444 val |= TSADC_AUTO_CON_POL_HI;
446 val &= ~TSADC_AUTO_CON_POL_HI;
447 if (sc->conf->type == RK_TSADC_V3)
448 val |= TSADC_AUTO_Q_SEL;
449 WR4(sc, TSADC_AUTO_CON, val);
451 if (sc->conf->type == RK_TSADC_V2) {
453 WR4(sc, TSADC_AUTO_PERIOD, 250); /* 250 ms */
454 WR4(sc, TSADC_AUTO_PERIOD_HT, 50); /* 50 ms */
455 WR4(sc, TSADC_HIGHT_INT_DEBOUNCE, 4);
456 WR4(sc, TSADC_HIGHT_TSHUT_DEBOUNCE, 4);
459 if (sc->grf == NULL) {
460 /* Errata: adjust interleave to working value */
461 WR4(sc, TSADC_USER_CON, 13 << 6); /* 13 clks */
463 SYSCON_WRITE_4(sc->grf, GRF_TSADC_TESTBIT_L,
465 SYSCON_WRITE_4(sc->grf, GRF_TSADC_TESTBIT_H,
467 DELAY(30); /* 15 usec min */
469 SYSCON_WRITE_4(sc->grf, GRF_SARADC_TESTBIT,
470 GRF_SARADC_TESTBIT_ON);
471 SYSCON_WRITE_4(sc->grf, GRF_TSADC_TESTBIT_H,
472 GRF_TSADC_TESTBIT_H_ON);
473 DELAY(180); /* 90 usec min */
475 WR4(sc, TSADC_AUTO_PERIOD, 1875); /* 2.5 ms */
476 WR4(sc, TSADC_AUTO_PERIOD_HT, 1875); /* 2.5 ms */
477 WR4(sc, TSADC_HIGHT_INT_DEBOUNCE, 4);
478 WR4(sc, TSADC_HIGHT_TSHUT_DEBOUNCE, 4);
483 tsadc_read_temp(struct tsadc_softc *sc, struct tsensor *sensor, int *temp)
487 val = RD4(sc, TSADC_DATA(sensor->channel));
488 *temp = tsadc_raw_to_temp(sc, val);
491 printf("%s: Sensor(id: %d, ch: %d), temp: %d\n", __func__,
492 sensor->id, sensor->channel, *temp);
493 printf(" status: 0x%08X, 0x%08X\n",
494 RD4(sc, TSADC_USER_CON),
495 RD4(sc, TSADC_AUTO_CON));
496 printf(" Data: 0x%08X, 0x%08X, 0x%08X\n",
497 RD4(sc, TSADC_DATA(sensor->channel)),
498 RD4(sc, TSADC_COMP_INT(sensor->channel)),
499 RD4(sc, TSADC_COMP_SHUT(sensor->channel)));
505 tsadc_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
507 struct tsadc_softc *sc;
510 sc = device_get_softc(dev);
512 if (id >= sc->conf->ntsensors)
515 for (i = 0; i < sc->conf->ntsensors; i++) {
516 if (sc->conf->tsensors->id == id) {
517 rv =tsadc_read_temp(sc, sc->conf->tsensors + id, val);
525 tsadc_sysctl_temperature(SYSCTL_HANDLER_ARGS)
527 struct tsadc_softc *sc;
533 if (req->newptr != NULL)
539 if (id >= sc->conf->ntsensors)
541 rv = tsadc_read_temp(sc, sc->conf->tsensors + id, &val);
547 rv = sysctl_handle_int(oidp, &val, 0, req);
552 tsadc_init_sysctl(struct tsadc_softc *sc)
555 struct sysctl_oid *oid, *tmp;
557 sysctl_ctx_init(&tsadc_sysctl_ctx);
558 /* create node for hw.temp */
559 oid = SYSCTL_ADD_NODE(&tsadc_sysctl_ctx,
560 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
561 CTLFLAG_RD, NULL, "");
566 for (i = sc->conf->ntsensors - 1; i >= 0; i--) {
567 tmp = SYSCTL_ADD_PROC(&tsadc_sysctl_ctx,
568 SYSCTL_CHILDREN(oid), OID_AUTO, sc->conf->tsensors[i].name,
569 CTLTYPE_INT | CTLFLAG_RD, sc, i,
570 tsadc_sysctl_temperature, "IK", "SoC Temperature");
579 tsadc_intr(void *arg)
581 struct tsadc_softc *sc;
584 sc = (struct tsadc_softc *)arg;
586 val = RD4(sc, TSADC_INT_PD);
587 WR4(sc, TSADC_INT_PD, val);
589 /* XXX Handle shutdown and alarm interrupts. */
591 device_printf(sc->dev, "Alarm: device temperature "
592 "is above of shutdown level.\n");
593 } else if (val & 0x000F) {
594 device_printf(sc->dev, "Alarm: device temperature "
595 "is above of alarm level.\n");
597 return (FILTER_HANDLED);
601 tsadc_probe(device_t dev)
604 if (!ofw_bus_status_okay(dev))
607 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
610 device_set_desc(dev, "RockChip temperature sensors");
611 return (BUS_PROBE_DEFAULT);
615 tsadc_attach(device_t dev)
617 struct tsadc_softc *sc;
622 sc = device_get_softc(dev);
624 node = ofw_bus_get_node(sc->dev);
625 sc->conf = (struct tsadc_conf *)
626 ofw_bus_search_compatible(dev, compat_data)->ocd_data;
627 sc->alarm_temp = 90000;
630 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
632 if (sc->mem_res == NULL) {
633 device_printf(dev, "Cannot allocate memory resources\n");
638 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
639 if (sc->irq_res == NULL) {
640 device_printf(dev, "Cannot allocate IRQ resources\n");
644 if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
645 tsadc_intr, NULL, sc, &sc->irq_ih))) {
647 "WARNING: unable to register interrupt handler\n");
652 rv = hwreset_get_by_ofw_name(dev, 0, "tsadc-apb", &sc->hwreset);
654 device_printf(dev, "Cannot get 'tsadc-apb' reset\n");
657 rv = clk_get_by_ofw_name(dev, 0, "tsadc", &sc->tsadc_clk);
659 device_printf(dev, "Cannot get 'tsadc' clock: %d\n", rv);
662 rv = clk_get_by_ofw_name(dev, 0, "apb_pclk", &sc->apb_pclk_clk);
664 device_printf(dev, "Cannot get 'apb_pclk' clock: %d\n", rv);
668 /* grf is optional */
669 rv = syscon_get_by_ofw_property(dev, node, "rockchip,grf", &sc->grf);
670 if (rv != 0 && rv != ENOENT) {
671 device_printf(dev, "Cannot get 'grf' syscon: %d\n", rv);
675 rv = OF_getencprop(node, "rockchip,hw-tshut-temp",
676 &sc->shutdown_temp, sizeof(sc->shutdown_temp));
678 sc->shutdown_temp = sc->conf->shutdown_temp;
680 rv = OF_getencprop(node, "rockchip,hw-tshut-mode",
681 &sc->shutdown_mode, sizeof(sc->shutdown_mode));
683 sc->shutdown_mode = sc->conf->shutdown_mode;
685 rv = OF_getencprop(node, "rockchip,hw-tshut-polarity",
686 &sc->shutdown_pol, sizeof(sc->shutdown_pol));
688 sc->shutdown_pol = sc->conf->shutdown_pol;
690 /* Wakeup controller */
691 rv = hwreset_assert(sc->hwreset);
693 device_printf(dev, "Cannot assert reset\n");
697 /* Set the assigned clocks parent and freq */
698 if (clk_set_assigned(sc->dev, node) != 0) {
699 device_printf(dev, "clk_set_assigned failed\n");
703 rv = clk_enable(sc->tsadc_clk);
705 device_printf(dev, "Cannot enable 'tsadc_clk' clock: %d\n", rv);
708 rv = clk_enable(sc->apb_pclk_clk);
710 device_printf(dev, "Cannot enable 'apb_pclk' clock: %d\n", rv);
713 rv = hwreset_deassert(sc->hwreset);
715 device_printf(dev, "Cannot deassert reset\n");
720 for (i = 0; i < sc->conf->ntsensors; i++)
721 tsadc_init_tsensor(sc, sc->conf->tsensors + i);
723 /* Enable auto mode */
724 val = RD4(sc, TSADC_AUTO_CON);
725 val |= TSADC_AUTO_CON_AUTO;
726 WR4(sc, TSADC_AUTO_CON, val);
728 rv = tsadc_init_sysctl(sc);
730 device_printf(sc->dev, "Cannot initialize sysctls\n");
734 OF_device_register_xref(OF_xref_from_node(node), dev);
735 return (bus_generic_attach(dev));
738 sysctl_ctx_free(&tsadc_sysctl_ctx);
740 if (sc->irq_ih != NULL)
741 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
742 if (sc->tsadc_clk != NULL)
743 clk_release(sc->tsadc_clk);
744 if (sc->apb_pclk_clk != NULL)
745 clk_release(sc->apb_pclk_clk);
746 if (sc->hwreset != NULL)
747 hwreset_release(sc->hwreset);
748 if (sc->irq_res != NULL)
749 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
750 if (sc->mem_res != NULL)
751 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
757 tsadc_detach(device_t dev)
759 struct tsadc_softc *sc;
760 sc = device_get_softc(dev);
762 if (sc->irq_ih != NULL)
763 bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
764 sysctl_ctx_free(&tsadc_sysctl_ctx);
765 if (sc->tsadc_clk != NULL)
766 clk_release(sc->tsadc_clk);
767 if (sc->apb_pclk_clk != NULL)
768 clk_release(sc->apb_pclk_clk);
769 if (sc->hwreset != NULL)
770 hwreset_release(sc->hwreset);
771 if (sc->irq_res != NULL)
772 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
773 if (sc->mem_res != NULL)
774 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
779 static device_method_t rk_tsadc_methods[] = {
780 /* Device interface */
781 DEVMETHOD(device_probe, tsadc_probe),
782 DEVMETHOD(device_attach, tsadc_attach),
783 DEVMETHOD(device_detach, tsadc_detach),
785 /* TSADC interface */
786 DEVMETHOD(rk_tsadc_get_temperature, tsadc_get_temp),
791 static devclass_t rk_tsadc_devclass;
792 static DEFINE_CLASS_0(rk_tsadc, rk_tsadc_driver, rk_tsadc_methods,
793 sizeof(struct tsadc_softc));
794 EARLY_DRIVER_MODULE(rk_tsadc, simplebus, rk_tsadc_driver,
795 rk_tsadc_devclass, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_LAST);