Author: mmel
Date: Thu Nov 28 17:01:31 2019
New Revision: 355173
URL: https://svnweb.freebsd.org/changeset/base/355173

Log:
  Add driver for temperature sensors found in RK32898, RK3328 and RK3399 SoC's.
  
  MFC after:    3 weeks
  Reviewed by:  manu
  Differential Revision:  https://reviews.freebsd.org/D22442

Added:
  head/sys/arm64/rockchip/rk_tsadc.c   (contents, props changed)
  head/sys/arm64/rockchip/rk_tsadc_if.m   (contents, props changed)
Modified:
  head/sys/conf/files.arm64

Added: head/sys/arm64/rockchip/rk_tsadc.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/arm64/rockchip/rk_tsadc.c  Thu Nov 28 17:01:31 2019        
(r355173)
@@ -0,0 +1,794 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Michal Meloun <m...@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Thermometer and thermal zones driver for RockChip SoCs.
+ * Calibration data are taken from Linux, because this part of SoC
+ * is undocumented in TRM.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <machine/bus.h>
+
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/hwreset/hwreset.h>
+#include <dev/extres/syscon/syscon.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "syscon_if.h"
+#include "rk_tsadc_if.h"
+
+/* Global registers */
+#define        TSADC_USER_CON                          0x000
+#define        TSADC_AUTO_CON                          0x004
+#define         TSADC_AUTO_CON_POL_HI                          (1 << 8)
+#define         TSADC_AUTO_SRC_EN(x)                           (1 << (4 + (x)))
+#define         TSADC_AUTO_Q_SEL                               (1 << 1) /* V3 
only */
+#define         TSADC_AUTO_CON_AUTO                            (1 << 0)
+
+#define        TSADC_INT_EN                            0x008
+#define         TSADC_INT_EN_2CRU_EN_SRC(x)                    (1 << (8 + (x)))
+#define         TSADC_INT_EN_2GPIO_EN_SRC(x)                   (1 << (4 + (x)))
+#define        TSADC_INT_PD                            0x00c
+#define        TSADC_DATA(x)                           (0x20 + (x) * 0x04)
+#define        TSADC_COMP_INT(x)                       (0x30 + (x) * 0x04)
+#define         TSADC_COMP_INT_SRC_EN(x)                       (1 << (0 + (x)))
+#define        TSADC_COMP_SHUT(x)                      (0x40 + (x) * 0x04)
+#define        TSADC_HIGHT_INT_DEBOUNCE                0x060
+#define        TSADC_HIGHT_TSHUT_DEBOUNCE              0x064
+#define        TSADC_AUTO_PERIOD                       0x068
+#define        TSADC_AUTO_PERIOD_HT                    0x06c
+#define        TSADC_COMP0_LOW_INT                     0x080   /* V3 only */
+#define        TSADC_COMP1_LOW_INT                     0x084   /* V3 only */
+
+/* GFR Bits */
+#define        GRF_SARADC_TESTBIT                      0x0e644
+#define         GRF_SARADC_TESTBIT_ON                          (0x10001 << 2)
+#define GRF_TSADC_TESTBIT_L                    0x0e648
+#define         GRF_TSADC_VCM_EN_L                             (0x10001 << 7)
+#define        GRF_TSADC_TESTBIT_H                     0x0e64c
+#define         GRF_TSADC_VCM_EN_H                             (0x10001 << 7)
+#define         GRF_TSADC_TESTBIT_H_ON                         (0x10001 << 2)
+
+#define        WR4(_sc, _r, _v)        bus_write_4((_sc)->mem_res, (_r), (_v))
+#define        RD4(_sc, _r)            bus_read_4((_sc)->mem_res, (_r))
+
+static struct sysctl_ctx_list tsadc_sysctl_ctx;
+
+struct tsensor {
+       char                    *name;
+       int                     id;
+       int                     channel;
+};
+
+enum tsadc_type {
+       RK_TSADC_V2,
+       RK_TSADC_V3
+};
+
+struct rk_calib_entry {
+       uint32_t        raw;
+       int             temp;
+};
+
+struct tsadc_calib_info {
+       bool decrement_mode;
+       struct rk_calib_entry   *table;
+       int                     nentries;
+};
+
+struct tsadc_conf {
+       enum tsadc_type         type;
+       int                     shutdown_temp;
+       int                     shutdown_mode;
+       int                     shutdown_pol;
+       struct tsensor          *tsensors;
+       int                     ntsensors;
+       struct tsadc_calib_info calib_info;
+};
+
+struct tsadc_softc {
+       device_t                dev;
+       struct resource         *mem_res;
+       struct resource         *irq_res;
+       void                    *irq_ih;
+
+       clk_t                   tsadc_clk;
+       clk_t                   apb_pclk_clk;
+       hwreset_t               hwreset;
+       struct syscon           *grf;
+
+       struct tsadc_conf       *conf;
+
+       int                     shutdown_temp;
+       int                     shutdown_mode;
+       int                     shutdown_pol;
+
+       int                     alarm_temp;
+};
+
+static struct rk_calib_entry rk3288_calib_data[] = {
+       {3800, -40000},
+       {3792, -35000},
+       {3783, -30000},
+       {3774, -25000},
+       {3765, -20000},
+       {3756, -15000},
+       {3747, -10000},
+       {3737, -5000},
+       {3728, 0},
+       {3718, 5000},
+       {3708, 10000},
+       {3698, 15000},
+       {3688, 20000},
+       {3678, 25000},
+       {3667, 30000},
+       {3656, 35000},
+       {3645, 40000},
+       {3634, 45000},
+       {3623, 50000},
+       {3611, 55000},
+       {3600, 60000},
+       {3588, 65000},
+       {3575, 70000},
+       {3563, 75000},
+       {3550, 80000},
+       {3537, 85000},
+       {3524, 90000},
+       {3510, 95000},
+       {3496, 100000},
+       {3482, 105000},
+       {3467, 110000},
+       {3452, 115000},
+       {3437, 120000},
+       {3421, 125000},
+};
+
+struct tsensor rk3288_tsensors[] = {
+       { .channel = 0, .id = 2, .name = "reserved"},
+       { .channel = 1, .id = 0, .name = "CPU"},
+       { .channel = 2, .id = 1, .name = "GPU"},
+};
+
+struct tsadc_conf rk3288_tsadc_conf = {
+       .type =                 RK_TSADC_V2,
+       .shutdown_temp =        95000,
+       .shutdown_mode =        1, /* GPIO */
+       .shutdown_pol =         0, /* Low  */
+       .tsensors =             rk3288_tsensors,
+       .ntsensors =            nitems(rk3288_tsensors),
+       .calib_info =   {
+                       .table = rk3288_calib_data,
+                       .nentries = nitems(rk3288_calib_data),
+       }
+};
+
+static struct rk_calib_entry rk3328_calib_data[] = {
+       {296, -40000},
+       {304, -35000},
+       {313, -30000},
+       {331, -20000},
+       {340, -15000},
+       {349, -10000},
+       {359, -5000},
+       {368, 0},
+       {378, 5000},
+       {388, 10000},
+       {398, 15000},
+       {408, 20000},
+       {418, 25000},
+       {429, 30000},
+       {440, 35000},
+       {451, 40000},
+       {462, 45000},
+       {473, 50000},
+       {485, 55000},
+       {496, 60000},
+       {508, 65000},
+       {521, 70000},
+       {533, 75000},
+       {546, 80000},
+       {559, 85000},
+       {572, 90000},
+       {586, 95000},
+       {600, 100000},
+       {614, 105000},
+       {629, 110000},
+       {644, 115000},
+       {659, 120000},
+       {675, 125000},
+};
+
+static struct tsensor rk3328_tsensors[] = {
+       { .channel = 0, .id = 0, .name = "CPU"},
+};
+
+static struct tsadc_conf rk3328_tsadc_conf = {
+       .type =                 RK_TSADC_V3,
+       .shutdown_temp =        95000,
+       .shutdown_mode =        0, /* CRU */
+       .shutdown_pol =         0, /* Low  */
+       .tsensors =             rk3328_tsensors,
+       .ntsensors =            nitems(rk3328_tsensors),
+       .calib_info =   {
+                       .table = rk3328_calib_data,
+                       .nentries = nitems(rk3328_calib_data),
+       }
+};
+
+static struct rk_calib_entry rk3399_calib_data[] = {
+       {402, -40000},
+       {410, -35000},
+       {419, -30000},
+       {427, -25000},
+       {436, -20000},
+       {444, -15000},
+       {453, -10000},
+       {461, -5000},
+       {470, 0},
+       {478, 5000},
+       {487, 10000},
+       {496, 15000},
+       {504, 20000},
+       {513, 25000},
+       {521, 30000},
+       {530, 35000},
+       {538, 40000},
+       {547, 45000},
+       {555, 50000},
+       {564, 55000},
+       {573, 60000},
+       {581, 65000},
+       {590, 70000},
+       {599, 75000},
+       {607, 80000},
+       {616, 85000},
+       {624, 90000},
+       {633, 95000},
+       {642, 100000},
+       {650, 105000},
+       {659, 110000},
+       {668, 115000},
+       {677, 120000},
+       {685, 125000},
+};
+
+static struct tsensor rk3399_tsensors[] = {
+       { .channel = 0, .id = 0, .name = "CPU"},
+       { .channel = 1, .id = 1, .name = "GPU"},
+};
+
+static struct tsadc_conf rk3399_tsadc_conf = {
+       .type =                 RK_TSADC_V3,
+       .shutdown_temp =        95000,
+       .shutdown_mode =        1, /* GPIO */
+       .shutdown_pol =         0, /* Low  */
+       .tsensors =             rk3399_tsensors,
+       .ntsensors =            nitems(rk3399_tsensors),
+       .calib_info =   {
+                       .table = rk3399_calib_data,
+                       .nentries = nitems(rk3399_calib_data),
+       }
+};
+
+static struct ofw_compat_data compat_data[] = {
+       {"rockchip,rk3288-tsadc",       (uintptr_t)&rk3288_tsadc_conf},
+       {"rockchip,rk3328-tsadc",       (uintptr_t)&rk3328_tsadc_conf},
+       {"rockchip,rk3399-tsadc",       (uintptr_t)&rk3399_tsadc_conf},
+       {NULL,          0}
+};
+
+static uint32_t
+tsadc_temp_to_raw(struct tsadc_softc *sc, int temp)
+{
+       struct rk_calib_entry *tbl;
+       int denom, ntbl, raw, i;
+
+       tbl = sc->conf->calib_info.table;
+       ntbl = sc->conf->calib_info.nentries;
+
+       if (temp <= tbl[0].temp)
+               return (tbl[0].raw);
+
+       if (temp >= tbl[ntbl - 1].temp)
+               return (tbl[ntbl - 1].raw);
+
+       for (i = 1; i < (ntbl - 1); i++) {
+               /* Exact match */
+               if (temp == tbl[i].temp)
+                       return (tbl[i].raw);
+               if (temp < tbl[i].temp)
+                       break;
+       }
+
+       /*
+       * Translated value is between i and i - 1 table entries.
+       * Do linear interpolation for it.
+       */
+       raw = (int)tbl[i - 1].raw - (int)tbl[i].raw;
+       raw *= temp - tbl[i - 1].temp;
+       denom = tbl[i - 1].temp - tbl[i].temp;
+       raw = tbl[i - 1].raw + raw / denom;
+       return (raw);
+}
+
+static int
+tsadc_raw_to_temp(struct tsadc_softc *sc, uint32_t raw)
+{
+       struct rk_calib_entry *tbl;
+       int denom, ntbl, temp, i;
+       bool descending;
+
+       tbl = sc->conf->calib_info.table;
+       ntbl = sc->conf->calib_info.nentries;
+       descending = tbl[0].raw > tbl[1].raw;
+
+       if (descending) {
+               /* Raw column is in descending order. */
+               if (raw >= tbl[0].raw)
+                       return (tbl[0].temp);
+               if (raw <= tbl[ntbl - 1].raw)
+                       return (tbl[ntbl - 1].temp);
+
+               for (i = ntbl - 2; i > 0; i--) {
+                       /* Exact match */
+                       if (raw == tbl[i].raw)
+                               return (tbl[i].temp);
+                       if (raw < tbl[i].raw)
+                               break;
+               }
+       } else {
+               /* Raw column is in ascending order. */
+               if (raw <= tbl[0].raw)
+                       return (tbl[0].temp);
+               if (raw >= tbl[ntbl - 1].raw)
+                       return (tbl[ntbl - 1].temp);
+               for (i = 1; i < (ntbl - 1); i++) {
+                       /* Exact match */
+                       if (raw == tbl[i].raw)
+                               return (tbl[i].temp);
+                       if (raw < tbl[i].raw)
+                               break;
+               }
+       }
+
+
+       /*
+       * Translated value is between i and i - 1 table entries.
+       * Do linear interpolation for it.
+       */
+       temp  = (int)tbl[i - 1].temp - (int)tbl[i].temp;
+       temp *= raw - tbl[i - 1].raw;
+       denom = tbl[i - 1].raw - tbl[i].raw;
+       temp = tbl[i - 1].temp + temp / denom;
+       return (temp);
+}
+
+static void
+tsadc_init_tsensor(struct tsadc_softc *sc, struct tsensor *sensor)
+{
+       uint32_t val;
+
+       /* Shutdown mode */
+       val = RD4(sc, TSADC_INT_EN);
+       if (sc->shutdown_mode != 0) {
+               /* Signal shutdown of GPIO pin */
+               val &= ~TSADC_INT_EN_2CRU_EN_SRC(sensor->channel);
+               val |= TSADC_INT_EN_2GPIO_EN_SRC(sensor->channel);
+       } else {
+               val |= TSADC_INT_EN_2CRU_EN_SRC(sensor->channel);
+               val &= ~TSADC_INT_EN_2GPIO_EN_SRC(sensor->channel);
+       }
+       WR4(sc, TSADC_INT_EN, val);
+
+       /* Shutdown temperature */
+       val =  tsadc_raw_to_temp(sc, sc->shutdown_temp);
+       WR4(sc, TSADC_COMP_SHUT(sensor->channel), val);
+       val = RD4(sc, TSADC_AUTO_CON);
+       val |= TSADC_AUTO_SRC_EN(sensor->channel);
+       WR4(sc, TSADC_AUTO_CON, val);
+
+       /* Alarm temperature */
+       val =  tsadc_temp_to_raw(sc, sc->alarm_temp);
+       WR4(sc, TSADC_COMP_INT(sensor->channel), val);
+       val = RD4(sc, TSADC_INT_EN);
+       val |= TSADC_COMP_INT_SRC_EN(sensor->channel);
+       WR4(sc, TSADC_INT_EN, val);
+}
+
+static void
+tsadc_init(struct tsadc_softc *sc)
+{
+       uint32_t val;
+
+       /* Common part */
+       val = 0;        /* XXX Is this right? */
+       if (sc->shutdown_pol != 0)
+               val |= TSADC_AUTO_CON_POL_HI;
+       else
+               val &= ~TSADC_AUTO_CON_POL_HI;
+       if (sc->conf->type == RK_TSADC_V3)
+               val |= TSADC_AUTO_Q_SEL;
+       WR4(sc, TSADC_AUTO_CON, val);
+
+       if (sc->conf->type == RK_TSADC_V2) {
+               /* V2 init */
+               WR4(sc, TSADC_AUTO_PERIOD, 250);        /* 250 ms */
+               WR4(sc, TSADC_AUTO_PERIOD_HT, 50);      /*  50 ms */
+               WR4(sc, TSADC_HIGHT_INT_DEBOUNCE, 4);
+               WR4(sc, TSADC_HIGHT_TSHUT_DEBOUNCE, 4);
+       } else {
+               /* V3 init */
+               if (sc->grf == NULL) {
+                       /* Errata: adjust interleave to working value */
+                       WR4(sc, TSADC_USER_CON, 13 << 6);       /* 13 clks */
+               } else {
+                       SYSCON_WRITE_4(sc->grf, GRF_TSADC_TESTBIT_L,
+                           GRF_TSADC_VCM_EN_L);
+                       SYSCON_WRITE_4(sc->grf, GRF_TSADC_TESTBIT_H,
+                           GRF_TSADC_VCM_EN_H);
+                       DELAY(30);  /* 15 usec min */
+
+                       SYSCON_WRITE_4(sc->grf, GRF_SARADC_TESTBIT,
+                           GRF_SARADC_TESTBIT_ON);
+                       SYSCON_WRITE_4(sc->grf, GRF_TSADC_TESTBIT_H,
+                           GRF_TSADC_TESTBIT_H_ON);
+                       DELAY(180);  /* 90 usec min */
+               }
+               WR4(sc, TSADC_AUTO_PERIOD, 1875);       /* 2.5 ms */
+               WR4(sc, TSADC_AUTO_PERIOD_HT, 1875);    /* 2.5 ms */
+               WR4(sc, TSADC_HIGHT_INT_DEBOUNCE, 4);
+               WR4(sc, TSADC_HIGHT_TSHUT_DEBOUNCE, 4);
+       }
+}
+
+static int
+tsadc_read_temp(struct tsadc_softc *sc, struct tsensor *sensor, int *temp)
+{
+       uint32_t val;
+
+       val = RD4(sc, TSADC_DATA(sensor->channel));
+       *temp = tsadc_raw_to_temp(sc, val);
+
+#ifdef DEBUG
+       printf("%s: Sensor(id: %d, ch: %d), temp: %d\n", __func__,
+           sensor->id, sensor->channel, *temp);
+       printf(" status: 0x%08X, 0x%08X\n",
+           RD4(sc, TSADC_USER_CON),
+           RD4(sc, TSADC_AUTO_CON));
+       printf(" Data: 0x%08X, 0x%08X, 0x%08X\n",
+           RD4(sc, TSADC_DATA(sensor->channel)),
+           RD4(sc, TSADC_COMP_INT(sensor->channel)),
+           RD4(sc, TSADC_COMP_SHUT(sensor->channel)));
+#endif
+       return (0);
+}
+
+static int
+tsadc_get_temp(device_t dev, device_t cdev, uintptr_t id, int *val)
+{
+       struct tsadc_softc *sc;
+       int i, rv;
+
+       sc = device_get_softc(dev);
+
+       if (id >= sc->conf->ntsensors)
+               return (ERANGE);
+
+       for (i = 0; i < sc->conf->ntsensors; i++) {
+               if (sc->conf->tsensors->id == id) {
+                       rv =tsadc_read_temp(sc, sc->conf->tsensors + id, val);
+                       return (rv);
+               }
+       }
+       return (ERANGE);
+}
+
+static int
+tsadc_sysctl_temperature(SYSCTL_HANDLER_ARGS)
+{
+       struct tsadc_softc *sc;
+       int val;
+       int rv;
+       int id;
+
+       /* Write request */
+       if (req->newptr != NULL)
+               return (EINVAL);
+
+       sc = arg1;
+       id = arg2;
+
+       if (id >= sc->conf->ntsensors)
+               return (ERANGE);
+       rv =  tsadc_read_temp(sc, sc->conf->tsensors + id, &val);
+       if (rv != 0)
+               return (rv);
+
+       val = val / 100;
+       val +=  2731;
+       rv = sysctl_handle_int(oidp, &val, 0, req);
+       return (rv);
+}
+
+static int
+tsadc_init_sysctl(struct tsadc_softc *sc)
+{
+       int i;
+       struct sysctl_oid *oid, *tmp;
+
+       sysctl_ctx_init(&tsadc_sysctl_ctx);
+       /* create node for hw.temp */
+       oid = SYSCTL_ADD_NODE(&tsadc_sysctl_ctx,
+           SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature",
+           CTLFLAG_RD, NULL, "");
+       if (oid == NULL)
+               return (ENXIO);
+
+       /* Add sensors */
+       for (i = sc->conf->ntsensors  - 1; i >= 0; i--) {
+               tmp = SYSCTL_ADD_PROC(&tsadc_sysctl_ctx,
+                   SYSCTL_CHILDREN(oid), OID_AUTO, sc->conf->tsensors[i].name,
+                   CTLTYPE_INT | CTLFLAG_RD, sc, i,
+                   tsadc_sysctl_temperature, "IK", "SoC Temperature");
+               if (tmp == NULL)
+                       return (ENXIO);
+       }
+
+       return (0);
+}
+
+static int
+tsadc_intr(void *arg)
+{
+       struct tsadc_softc *sc;
+       uint32_t val;
+
+       sc = (struct tsadc_softc *)arg;
+
+       val = RD4(sc, TSADC_INT_PD);
+       WR4(sc, TSADC_INT_PD, val);
+
+       /* XXX Handle shutdown and alarm interrupts. */
+       if (val & 0x00F0) {
+               device_printf(sc->dev, "Alarm: device temperature "
+                   "is above of shutdown level.\n");
+       } else if (val & 0x000F) {
+               device_printf(sc->dev, "Alarm: device temperature "
+                   "is above of alarm level.\n");
+       }
+       return (FILTER_HANDLED);
+}
+
+static int
+tsadc_probe(device_t dev)
+{
+
+       if (!ofw_bus_status_okay(dev))
+               return (ENXIO);
+
+       if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
+               return (ENXIO);
+
+       device_set_desc(dev, "RockChip temperature sensors");
+       return (BUS_PROBE_DEFAULT);
+}
+
+static int
+tsadc_attach(device_t dev)
+{
+       struct tsadc_softc *sc;
+       phandle_t node;
+       uint32_t val;
+       int i, rid, rv;
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+       node = ofw_bus_get_node(sc->dev);
+       sc->conf = (struct tsadc_conf *)
+           ofw_bus_search_compatible(dev, compat_data)->ocd_data;
+       sc->alarm_temp = 90000;
+
+       rid = 0;
+       sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+           RF_ACTIVE);
+       if (sc->mem_res == NULL) {
+               device_printf(dev, "Cannot allocate memory resources\n");
+               goto fail;
+       }
+
+       rid = 0;
+       sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
+       if (sc->irq_res == NULL) {
+               device_printf(dev, "Cannot allocate IRQ resources\n");
+               goto fail;
+       }
+
+       if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+           tsadc_intr, NULL, sc, &sc->irq_ih))) {
+               device_printf(dev,
+                   "WARNING: unable to register interrupt handler\n");
+               goto fail;
+       }
+
+       /* FDT resources */
+       rv = hwreset_get_by_ofw_name(dev, 0, "tsadc-apb", &sc->hwreset);
+       if (rv != 0) {
+               device_printf(dev, "Cannot get 'tsadc-apb' reset\n");
+               goto fail;
+       }
+       rv = clk_get_by_ofw_name(dev, 0, "tsadc", &sc->tsadc_clk);
+       if (rv != 0) {
+               device_printf(dev, "Cannot get 'tsadc' clock: %d\n", rv);
+               goto fail;
+       }
+       rv = clk_get_by_ofw_name(dev, 0, "apb_pclk", &sc->apb_pclk_clk);
+       if (rv != 0) {
+               device_printf(dev, "Cannot get 'apb_pclk' clock: %d\n", rv);
+               goto fail;
+       }
+
+       /* grf is optional */
+       rv = syscon_get_by_ofw_property(dev, node, "rockchip,grf", &sc->grf);
+       if (rv != 0 && rv != ENOENT) {
+               device_printf(dev, "Cannot get 'grf' syscon: %d\n", rv);
+               goto fail;
+       }
+
+       rv = OF_getencprop(node, "rockchip,hw-tshut-temp",
+           &sc->shutdown_temp, sizeof(sc->shutdown_temp));
+       if (rv <= 0)
+               sc->shutdown_temp = sc->conf->shutdown_temp;
+
+       rv = OF_getencprop(node, "rockchip,hw-tshut-mode",
+           &sc->shutdown_mode, sizeof(sc->shutdown_mode));
+       if (rv <= 0)
+               sc->shutdown_mode = sc->conf->shutdown_mode;
+
+       rv = OF_getencprop(node, "rockchip,hw-tshut-polarity",
+           &sc->shutdown_pol, sizeof(sc->shutdown_pol));
+       if (rv <= 0)
+               sc->shutdown_pol = sc->conf->shutdown_pol;
+
+       /* Wakeup controller */
+       rv = hwreset_assert(sc->hwreset);
+       if (rv != 0) {
+               device_printf(dev, "Cannot assert reset\n");
+               goto fail;
+       }
+
+       /* Set the assigned clocks parent and freq */
+       if (clk_set_assigned(sc->dev, node) != 0) {
+               device_printf(dev, "clk_set_assigned failed\n");
+               goto fail;
+       }
+
+       rv = clk_enable(sc->tsadc_clk);
+       if (rv != 0) {
+               device_printf(dev, "Cannot enable 'tsadc_clk' clock: %d\n", rv);
+               goto fail;
+       }
+       rv = clk_enable(sc->apb_pclk_clk);
+       if (rv != 0) {
+               device_printf(dev, "Cannot enable 'apb_pclk' clock: %d\n", rv);
+               goto fail;
+       }
+       rv = hwreset_deassert(sc->hwreset);
+       if (rv != 0) {
+               device_printf(dev, "Cannot deassert reset\n");
+               goto fail;
+       }
+
+       tsadc_init(sc);
+       for (i = 0; i < sc->conf->ntsensors; i++)
+               tsadc_init_tsensor(sc, sc->conf->tsensors + i);
+
+       /* Enable auto mode */
+       val = RD4(sc, TSADC_AUTO_CON);
+       val |= TSADC_AUTO_CON_AUTO;
+       WR4(sc, TSADC_AUTO_CON, val);
+
+       rv = tsadc_init_sysctl(sc);
+       if (rv != 0) {
+               device_printf(sc->dev, "Cannot initialize sysctls\n");
+               goto fail;
+       }
+
+       OF_device_register_xref(OF_xref_from_node(node), dev);
+       return (bus_generic_attach(dev));
+
+fail:
+       if (sc->irq_ih != NULL)
+               bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
+       sysctl_ctx_free(&tsadc_sysctl_ctx);
+       if (sc->tsadc_clk != NULL)
+               clk_release(sc->tsadc_clk);
+       if (sc->apb_pclk_clk != NULL)
+               clk_release(sc->apb_pclk_clk);
+       if (sc->hwreset != NULL)
+               hwreset_release(sc->hwreset);
+       if (sc->irq_res != NULL)
+               bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+       if (sc->mem_res != NULL)
+               bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+       return (ENXIO);
+}
+
+static int
+tsadc_detach(device_t dev)
+{
+       struct tsadc_softc *sc;
+       sc = device_get_softc(dev);
+
+       if (sc->irq_ih != NULL)
+               bus_teardown_intr(dev, sc->irq_res, sc->irq_ih);
+       sysctl_ctx_free(&tsadc_sysctl_ctx);
+       if (sc->tsadc_clk != NULL)
+               clk_release(sc->tsadc_clk);
+       if (sc->apb_pclk_clk != NULL)
+               clk_release(sc->apb_pclk_clk);
+       if (sc->hwreset != NULL)
+               hwreset_release(sc->hwreset);
+       if (sc->irq_res != NULL)
+               bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
+       if (sc->mem_res != NULL)
+               bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+
+       return (ENXIO);
+}
+
+static device_method_t rk_tsadc_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,                 tsadc_probe),
+       DEVMETHOD(device_attach,                tsadc_attach),
+       DEVMETHOD(device_detach,                tsadc_detach),
+
+       /* TSADC interface */
+       DEVMETHOD(rk_tsadc_get_temperature,     tsadc_get_temp),
+
+       DEVMETHOD_END
+};
+
+static devclass_t rk_tsadc_devclass;
+static DEFINE_CLASS_0(rk_tsadc, rk_tsadc_driver, rk_tsadc_methods,
+    sizeof(struct tsadc_softc));
+EARLY_DRIVER_MODULE(rk_tsadc, simplebus, rk_tsadc_driver,
+    rk_tsadc_devclass, NULL, NULL, BUS_PASS_TIMER + BUS_PASS_ORDER_LAST);

Added: head/sys/arm64/rockchip/rk_tsadc_if.m
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/sys/arm64/rockchip/rk_tsadc_if.m       Thu Nov 28 17:01:31 2019        
(r355173)
@@ -0,0 +1,43 @@
+#-
+# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+#
+# Copyright (c) 2019 Michal Meloun <m...@freebsd.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+#include <machine/bus.h>
+
+INTERFACE rk_tsadc;
+
+
+/**
+ * Read temperature
+ */
+METHOD int get_temperature{
+       device_t        dev;
+       device_t        consumer;
+       uintptr_t       id;
+       int             *val;
+};

Modified: head/sys/conf/files.arm64
==============================================================================
--- head/sys/conf/files.arm64   Thu Nov 28 12:50:25 2019        (r355172)
+++ head/sys/conf/files.arm64   Thu Nov 28 17:01:31 2019        (r355173)
@@ -307,6 +307,8 @@ arm64/rockchip/rk_spi.c                     optional fdt 
rk_spi
 arm64/rockchip/rk_usb2phy.c            optional fdt rk_usb2phy 
soc_rockchip_rk3328 | soc_rockchip_rk3399
 arm64/rockchip/rk_typec_phy.c          optional fdt rk_typec_phy 
soc_rockchip_rk3399
 arm64/rockchip/if_dwc_rk.c             optional fdt dwc_rk soc_rockchip_rk3328 
| fdt dwc_rk soc_rockchip_rk3399
+arm64/rockchip/rk_tsadc_if.m           optional fdt soc_rockchip_rk3399
+arm64/rockchip/rk_tsadc.c              optional fdt soc_rockchip_rk3399
 dev/dwc/if_dwc.c                       optional fdt dwc_rk soc_rockchip_rk3328 
| fdt dwc_rk soc_rockchip_rk3399
 dev/dwc/if_dwc_if.m                    optional fdt dwc_rk soc_rockchip_rk3328 
| fdt dwc_rk soc_rockchip_rk3399
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to