1 /* $OpenBSD: rktemp.c,v 1.1 2017/08/25 10:29:54 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2017 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/sensors.h> 22 23 #include <machine/intr.h> 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/ofw_clock.h> 29 #include <dev/ofw/ofw_misc.h> 30 #include <dev/ofw/ofw_pinctrl.h> 31 #include <dev/ofw/fdt.h> 32 33 /* Registers */ 34 #define TSADC_USER_CON 0x0000 35 #define TSADC_AUTO_CON 0x0004 36 #define TSADC_AUTO_CON_TSHUT_POLARITY (1 << 8) 37 #define TSADC_AUTO_CON_SRC1_EN (1 << 5) 38 #define TSADC_AUTO_CON_SRC0_EN (1 << 4) 39 #define TSADC_AUTO_CON_TSADC_Q_SEL (1 << 1) 40 #define TSADC_AUTO_CON_AUTO_EN (1 << 0) 41 #define TSADC_INT_EN 0x0008 42 #define TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 (1 << 9) 43 #define TSADC_INT_EN_TSHUT_2CRU_EN_SRC0 (1 << 8) 44 #define TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 (1 << 5) 45 #define TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0 (1 << 4) 46 #define TSADC_INT_PD 0x000c 47 #define TSADC_DATA0 0x0020 48 #define TSADC_DATA1 0x0024 49 #define TSADC_COMP0_INT 0x0030 50 #define TSADC_COMP1_INT 0x0034 51 #define TSADC_COMP0_SHUT 0x0040 52 #define TSADC_COMP1_SHUT 0x0044 53 #define TSADC_AUTO_PERIOD 0x0068 54 #define TSADC_AUTO_PERIOD_HT 0x006c 55 56 #define HREAD4(sc, reg) \ 57 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 58 #define HWRITE4(sc, reg, val) \ 59 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 60 61 struct rktemp_softc { 62 struct device sc_dev; 63 bus_space_tag_t sc_iot; 64 bus_space_handle_t sc_ioh; 65 66 struct ksensor sc_sensors[2]; 67 struct ksensordev sc_sensordev; 68 }; 69 70 int rktemp_match(struct device *, void *, void *); 71 void rktemp_attach(struct device *, struct device *, void *); 72 73 struct cfattach rktemp_ca = { 74 sizeof (struct rktemp_softc), rktemp_match, rktemp_attach 75 }; 76 77 struct cfdriver rktemp_cd = { 78 NULL, "rktemp", DV_DULL 79 }; 80 81 uint32_t rktemp_calc_code(int32_t); 82 int32_t rktemp_calc_temp(uint32_t); 83 int rktemp_valid(uint32_t); 84 void rktemp_refresh_sensors(void *); 85 86 int 87 rktemp_match(struct device *parent, void *match, void *aux) 88 { 89 struct fdt_attach_args *faa = aux; 90 91 return (OF_is_compatible(faa->fa_node, "rockchip,rk3399-tsadc")); 92 } 93 94 void 95 rktemp_attach(struct device *parent, struct device *self, void *aux) 96 { 97 struct rktemp_softc *sc = (struct rktemp_softc *)self; 98 struct fdt_attach_args *faa = aux; 99 uint32_t mode, polarity, temp; 100 uint32_t auto_con, int_en; 101 int node = faa->fa_node; 102 103 if (faa->fa_nreg < 1) { 104 printf(": no registers\n"); 105 return; 106 } 107 108 sc->sc_iot = faa->fa_iot; 109 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 110 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 111 printf(": can't map registers\n"); 112 return; 113 } 114 115 printf("\n"); 116 117 pinctrl_byname(node, "init"); 118 119 clock_enable(node, "tsadc"); 120 clock_enable(node, "apb_pclk"); 121 122 /* Reset the TS-ADC controller block. */ 123 reset_assert(node, "tsadc-apb"); 124 delay(10); 125 reset_deassert(node, "tsadc-apb"); 126 127 mode = OF_getpropint(node, "rockchip,hw-tshut-mode", 1); 128 polarity = OF_getpropint(node, "rockchip,hw-tshut-polarity", 0); 129 temp = OF_getpropint(node, "rockchip,hw-tshut-temp", 95000); 130 131 auto_con = HREAD4(sc, TSADC_AUTO_CON); 132 auto_con |= TSADC_AUTO_CON_TSADC_Q_SEL; 133 if (polarity) 134 auto_con |= TSADC_AUTO_CON_TSHUT_POLARITY; 135 HWRITE4(sc, TSADC_AUTO_CON, auto_con); 136 137 /* Configure mode. */ 138 int_en = HREAD4(sc, TSADC_INT_EN); 139 if (mode) { 140 int_en |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0; 141 int_en |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1; 142 } else { 143 int_en |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC0; 144 int_en |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC1; 145 } 146 HWRITE4(sc, TSADC_INT_EN, int_en); 147 148 /* Set shutdown limit. */ 149 HWRITE4(sc, TSADC_COMP0_SHUT, rktemp_calc_code(temp)); 150 auto_con |= TSADC_AUTO_CON_SRC0_EN; 151 HWRITE4(sc, TSADC_COMP1_SHUT, rktemp_calc_code(temp)); 152 auto_con |= TSADC_AUTO_CON_SRC1_EN; 153 HWRITE4(sc, TSADC_AUTO_CON, auto_con); 154 155 pinctrl_byname(faa->fa_node, "default"); 156 157 /* Finally turn on the ADC. */ 158 auto_con |= TSADC_AUTO_CON_AUTO_EN; 159 HWRITE4(sc, TSADC_AUTO_CON, auto_con); 160 161 /* Register sensors. */ 162 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 163 sizeof(sc->sc_sensordev.xname)); 164 strlcpy(sc->sc_sensors[0].desc, "CPU", sizeof(sc->sc_sensors[0].desc)); 165 sc->sc_sensors[0].type = SENSOR_TEMP; 166 sc->sc_sensors[0].flags = SENSOR_FINVALID; 167 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[0]); 168 strlcpy(sc->sc_sensors[1].desc, "GPU", sizeof(sc->sc_sensors[1].desc)); 169 sc->sc_sensors[1].type = SENSOR_TEMP; 170 sc->sc_sensors[1].flags = SENSOR_FINVALID; 171 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[1]); 172 sensordev_install(&sc->sc_sensordev); 173 sensor_task_register(sc, rktemp_refresh_sensors, 5); 174 } 175 176 struct rktemp_table_entry { 177 int32_t temp; 178 uint32_t code; 179 }; 180 181 /* RK3399 conversion table. */ 182 struct rktemp_table_entry rktemp_table[] = { 183 { -40000, 402 }, 184 { -35000, 410 }, 185 { -30000, 419 }, 186 { -25000, 427 }, 187 { -20000, 436 }, 188 { -15000, 444 }, 189 { -10000, 453 }, 190 { -5000, 461 }, 191 { 0, 470 }, 192 { 5000, 478 }, 193 { 10000, 487 }, 194 { 15000, 496 }, 195 { 20000, 504 }, 196 { 25000, 513 }, 197 { 30000, 521 }, 198 { 35000, 530 }, 199 { 40000, 538 }, 200 { 45000, 547 }, 201 { 50000, 555 }, 202 { 55000, 564 }, 203 { 60000, 573 }, 204 { 65000, 581 }, 205 { 70000, 590 }, 206 { 75000, 599 }, 207 { 80000, 607 }, 208 { 85000, 616 }, 209 { 90000, 624 }, 210 { 95000, 633 }, 211 { 100000, 642 }, 212 { 105000, 650 }, 213 { 110000, 659 }, 214 { 115000, 668 }, 215 { 120000, 677 }, 216 { 125000, 685 } 217 }; 218 219 uint32_t 220 rktemp_calc_code(int32_t temp) 221 { 222 const int n = nitems(rktemp_table); 223 uint32_t code0, delta_code; 224 int32_t temp0, delta_temp; 225 int i; 226 227 if (temp <= rktemp_table[0].temp) 228 return rktemp_table[0].code; 229 if (temp >= rktemp_table[n - 1].temp) 230 return rktemp_table[n - 1].code; 231 232 for (i = 1; i < n; i++) { 233 if (temp < rktemp_table[i].temp) 234 break; 235 } 236 237 code0 = rktemp_table[i - 1].code; 238 temp0 = rktemp_table[i - 1].temp; 239 delta_code = rktemp_table[i].code - code0; 240 delta_temp = rktemp_table[i].temp - temp0; 241 242 return code0 + (temp - temp0) * delta_code / delta_temp; 243 } 244 245 int32_t 246 rktemp_calc_temp(uint32_t code) 247 { 248 const int n = nitems(rktemp_table); 249 uint32_t code0, delta_code; 250 int32_t temp0, delta_temp; 251 int i; 252 253 if (code <= rktemp_table[0].code) 254 return rktemp_table[0].temp; 255 if (code >= rktemp_table[n - 1].code) 256 return rktemp_table[n - 1].temp; 257 258 for (i = 1; i < n; i++) { 259 if (code < rktemp_table[i].code) 260 break; 261 } 262 263 code0 = rktemp_table[i - 1].code; 264 temp0 = rktemp_table[i - 1].temp; 265 delta_code = rktemp_table[i].code - code0; 266 delta_temp = rktemp_table[i].temp - temp0; 267 268 return temp0 + (code - code0) * delta_temp / delta_code; 269 } 270 271 int 272 rktemp_valid(uint32_t code) 273 { 274 const int n = nitems(rktemp_table); 275 276 if (code < rktemp_table[0].code) 277 return 0; 278 if (code > rktemp_table[n - 1].code) 279 return 0; 280 return 1; 281 } 282 283 void 284 rktemp_refresh_sensors(void *arg) 285 { 286 struct rktemp_softc *sc = arg; 287 uint32_t code; 288 289 code = HREAD4(sc, TSADC_DATA0); 290 sc->sc_sensors[0].value = 1000 * rktemp_calc_temp(code) + 273150000; 291 if (rktemp_valid(code)) 292 sc->sc_sensors[0].flags &= ~SENSOR_FINVALID; 293 else 294 sc->sc_sensors[0].flags |= SENSOR_FINVALID; 295 296 code = HREAD4(sc, TSADC_DATA1); 297 sc->sc_sensors[1].value = 1000 * rktemp_calc_temp(code) + 273150000; 298 if (rktemp_valid(code)) 299 sc->sc_sensors[1].flags &= ~SENSOR_FINVALID; 300 else 301 sc->sc_sensors[1].flags |= SENSOR_FINVALID; 302 } 303