1 /* $OpenBSD: imxtemp.c,v 1.6 2021/03/25 04:12:01 jsg Exp $ */ 2 /* 3 * Copyright (c) 2014 Patrick Wildt <patrick@blueri.se> 4 * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/sensors.h> 23 #include <sys/timeout.h> 24 25 #include <machine/fdt.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/fdt.h> 29 #include <dev/ofw/ofw_misc.h> 30 31 /* registers */ 32 #define TEMPMON_TEMPSENSE0 0x180 33 #define TEMPMON_TEMPSENSE0_SET 0x184 34 #define TEMPMON_TEMPSENSE0_CLR 0x188 35 #define TEMPMON_TEMPSENSE0_TOG 0x18c 36 #define TEMPMON_TEMPSENSE1 0x190 37 #define TEMPMON_TEMPSENSE1_SET 0x194 38 #define TEMPMON_TEMPSENSE1_CLR 0x198 39 #define TEMPMON_TEMPSENSE1_TOG 0x19c 40 41 /* bits and bytes */ 42 #define TEMPMON_TEMPSENSE0_POWER_DOWN (1 << 0) 43 #define TEMPMON_TEMPSENSE0_MEASURE_TEMP (1 << 1) 44 #define TEMPMON_TEMPSENSE0_FINISHED (1 << 2) 45 #define TEMPMON_TEMPSENSE0_TEMP_CNT_MASK 0xfff 46 #define TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT 8 47 #define TEMPMON_TEMPSENSE0_ALARM_VALUE_MASK 0xfff 48 #define TEMPMON_TEMPSENSE0_ALARM_VALUE_SHIFT 20 49 50 /* calibration registers */ 51 #define OCOTP_ANA1 0x4e0 52 53 /* calibration bits and bytes */ 54 #define OCOTP_ANA1_HOT_TEMP_MASK 0xff 55 #define OCOTP_ANA1_HOT_TEMP_SHIFT 0 56 #define OCOTP_ANA1_HOT_COUNT_MASK 0xfff 57 #define OCOTP_ANA1_HOT_COUNT_SHIFT 8 58 #define OCOTP_ANA1_ROOM_COUNT_MASK 0xfff 59 #define OCOTP_ANA1_ROOM_COUNT_SHIFT 20 60 61 #define HREAD4(sc, reg) \ 62 regmap_read_4((sc)->sc_rm, (reg)) 63 #define HWRITE4(sc, reg, val) \ 64 regmap_write_4((sc)->sc_rm, (reg), (val)) 65 #define HSET4(sc, reg, bits) \ 66 HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 67 #define HCLR4(sc, reg, bits) \ 68 HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 69 70 struct imxtemp_softc { 71 struct device sc_dev; 72 int sc_node; 73 struct regmap *sc_rm; 74 75 uint32_t sc_hot_count; 76 uint32_t sc_hot_temp; 77 uint32_t sc_room_count; 78 79 struct ksensor sc_sensor; 80 struct ksensordev sc_sensordev; 81 struct timeout sc_sensorto; 82 }; 83 84 int imxtemp_match(struct device *, void *, void *); 85 void imxtemp_attach(struct device *, struct device *, void *); 86 87 struct cfattach imxtemp_ca = { 88 sizeof(struct imxtemp_softc), imxtemp_match, imxtemp_attach 89 }; 90 91 struct cfdriver imxtemp_cd = { 92 NULL, "imxtemp", DV_DULL 93 }; 94 95 void imxtemp_calibration(struct device *); 96 int32_t imxtemp_calc_temp(struct imxtemp_softc *, uint32_t); 97 void imxtemp_refresh_sensors(void *); 98 void imxtemp_pickup_sensors(void *); 99 100 int 101 imxtemp_match(struct device *parent, void *match, void *aux) 102 { 103 struct fdt_attach_args *faa = aux; 104 105 return OF_is_compatible(faa->fa_node, "fsl,imx6q-tempmon"); 106 } 107 108 void 109 imxtemp_attach(struct device *parent, struct device *self, void *aux) 110 { 111 struct imxtemp_softc *sc = (struct imxtemp_softc *)self; 112 struct fdt_attach_args *faa = aux; 113 uint32_t phandle; 114 115 sc->sc_node = faa->fa_node; 116 phandle = OF_getpropint(sc->sc_node, "fsl,tempmon", 0); 117 sc->sc_rm = regmap_byphandle(phandle); 118 if (sc->sc_rm == NULL) 119 return; 120 121 printf("\n"); 122 123 config_mountroot(self, imxtemp_calibration); 124 } 125 126 void 127 imxtemp_calibration(struct device *self) 128 { 129 struct imxtemp_softc *sc = (struct imxtemp_softc *)self; 130 uint32_t calibration; 131 uint32_t phandle; 132 struct regmap *rm; 133 134 phandle = OF_getpropint(sc->sc_node, "fsl,tempmon-data", 0); 135 rm = regmap_byphandle(phandle); 136 if (rm == NULL) 137 return; 138 139 calibration = regmap_read_4(rm, OCOTP_ANA1); 140 sc->sc_hot_count = (calibration >> OCOTP_ANA1_HOT_COUNT_SHIFT) & 141 OCOTP_ANA1_HOT_COUNT_MASK; 142 sc->sc_hot_temp = (calibration >> OCOTP_ANA1_HOT_TEMP_SHIFT) & 143 OCOTP_ANA1_HOT_TEMP_MASK; 144 sc->sc_room_count = (calibration >> OCOTP_ANA1_ROOM_COUNT_SHIFT) & 145 OCOTP_ANA1_ROOM_COUNT_MASK; 146 147 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 148 sizeof(sc->sc_sensordev.xname)); 149 strlcpy(sc->sc_sensor.desc, "core", 150 sizeof(sc->sc_sensor.desc)); 151 sc->sc_sensor.type = SENSOR_TEMP; 152 sc->sc_sensor.flags = SENSOR_FINVALID; 153 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 154 sensordev_install(&sc->sc_sensordev); 155 timeout_set(&sc->sc_sensorto, imxtemp_pickup_sensors, sc); 156 sensor_task_register(sc, imxtemp_refresh_sensors, 5); 157 } 158 159 int32_t 160 imxtemp_calc_temp(struct imxtemp_softc *sc, uint32_t temp_cnt) 161 { 162 int32_t value; 163 164 /* 165 * Calculate the calibrated tempterature based on the equation 166 * provided in the i.MX6 reference manual: 167 * 168 * Tmeas = HOT_TEMP - (Nmeas - HOT_COUNT) * ((HOT_TEMP - 25.0) / 169 * (ROOM_COUNT - HOT_COUNT)) 170 * 171 * Note that we calculate the temperature in uC to avoid loss 172 * of precision. 173 */ 174 value = ((sc->sc_hot_temp - 25) * 1000000) / 175 (sc->sc_room_count - sc->sc_hot_count); 176 value *= (temp_cnt - sc->sc_hot_count); 177 return ((sc->sc_hot_temp * 1000000) - value); 178 } 179 180 void 181 imxtemp_refresh_sensors(void *arg) 182 { 183 struct imxtemp_softc *sc = (struct imxtemp_softc *)arg; 184 185 timeout_del(&sc->sc_sensorto); 186 187 /* Power on temperature sensor. */ 188 HCLR4(sc, TEMPMON_TEMPSENSE0, TEMPMON_TEMPSENSE0_POWER_DOWN); 189 HSET4(sc, TEMPMON_TEMPSENSE0, TEMPMON_TEMPSENSE0_MEASURE_TEMP); 190 191 /* It may require up to ~17us to complete a measurement. */ 192 timeout_add_usec(&sc->sc_sensorto, 25); 193 } 194 195 void 196 imxtemp_pickup_sensors(void *arg) 197 { 198 struct imxtemp_softc *sc = (struct imxtemp_softc *)arg; 199 uint32_t value; 200 uint32_t temp_cnt; 201 202 value = HREAD4(sc, TEMPMON_TEMPSENSE0); 203 204 /* Power down temperature sensor. */ 205 HCLR4(sc, TEMPMON_TEMPSENSE0, TEMPMON_TEMPSENSE0_MEASURE_TEMP); 206 HSET4(sc, TEMPMON_TEMPSENSE0, TEMPMON_TEMPSENSE0_POWER_DOWN); 207 208 if ((value & TEMPMON_TEMPSENSE0_FINISHED) == 0) { 209 sc->sc_sensor.flags |= SENSOR_FINVALID; 210 return; 211 } 212 213 temp_cnt = (value >> TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT) & 214 TEMPMON_TEMPSENSE0_TEMP_CNT_MASK; 215 sc->sc_sensor.value = imxtemp_calc_temp(sc, temp_cnt) + 273150000; 216 sc->sc_sensor.flags &= ~SENSOR_FINVALID; 217 } 218