1 /* $OpenBSD: mvtemp.c,v 1.3 2022/06/28 23:43:12 naddy Exp $ */ 2 /* 3 * Copyright (c) 2018 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/bus.h> 24 #include <machine/fdt.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/fdt.h> 28 29 /* Registers */ 30 #define TEMP_STAT 0x0000 31 #define TEMP_CTRL0 0x0000 32 #define TEMP_CTRL0_TSEN_TC_TRIM_MASK 0x7 33 #define TEMP_CTRL0_TSEN_TC_TRIM_VAL 0x3 34 #define TEMP_CTRL1 0x0004 35 #define TEMP_CTRL1_TSEN_RESET (1 << 8) 36 37 struct mvtemp_softc { 38 struct device sc_dev; 39 bus_space_tag_t sc_iot; 40 bus_space_handle_t sc_stat_ioh; 41 bus_space_handle_t sc_ctrl_ioh; 42 43 uint32_t sc_stat_valid; 44 int32_t (*sc_calc_temp)(uint32_t); 45 46 struct ksensor sc_sensor; 47 struct ksensordev sc_sensordev; 48 }; 49 50 int mvtemp_match(struct device *, void *, void *); 51 void mvtemp_attach(struct device *, struct device *, void *); 52 53 const struct cfattach mvtemp_ca = { 54 sizeof (struct mvtemp_softc), mvtemp_match, mvtemp_attach 55 }; 56 57 struct cfdriver mvtemp_cd = { 58 NULL, "mvtemp", DV_DULL 59 }; 60 61 struct mvtemp_compat { 62 const char *compat; 63 uint32_t stat_valid; 64 void (*init)(struct mvtemp_softc *); 65 int32_t (*calc_temp)(uint32_t); 66 }; 67 68 void mvtemp_ap806_init(struct mvtemp_softc *); 69 int32_t mvtemp_ap806_calc_temp(uint32_t); 70 void mvtemp_cp110_init(struct mvtemp_softc *); 71 int32_t mvtemp_cp110_calc_temp(uint32_t); 72 73 const struct mvtemp_compat mvtemp_compat[] = { 74 { 75 "marvell,armada-ap806-thermal", (1 << 16), 76 mvtemp_ap806_init, mvtemp_ap806_calc_temp, 77 }, 78 { 79 "marvell,armada-cp110-thermal", (1 << 10), 80 mvtemp_cp110_init, mvtemp_cp110_calc_temp, 81 } 82 }; 83 84 void mvtemp_refresh_sensors(void *); 85 86 int 87 mvtemp_match(struct device *parent, void *match, void *aux) 88 { 89 struct fdt_attach_args *faa = aux; 90 int i; 91 92 for (i = 0; i < nitems(mvtemp_compat); i++) { 93 if (OF_is_compatible(faa->fa_node, mvtemp_compat[i].compat)) 94 return 1; 95 } 96 97 return 0; 98 } 99 100 void 101 mvtemp_attach(struct device *parent, struct device *self, void *aux) 102 { 103 struct mvtemp_softc *sc = (struct mvtemp_softc *)self; 104 struct fdt_attach_args *faa = aux; 105 int i; 106 107 if (faa->fa_nreg < 2) { 108 printf(": no registers\n"); 109 return; 110 } 111 112 sc->sc_iot = faa->fa_iot; 113 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 114 faa->fa_reg[0].size, 0, &sc->sc_stat_ioh)) { 115 printf(": can't map registers\n"); 116 return; 117 } 118 if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr, 119 faa->fa_reg[1].size, 0, &sc->sc_ctrl_ioh)) { 120 bus_space_unmap(sc->sc_iot, sc->sc_stat_ioh, 121 faa->fa_reg[0].size); 122 printf(": can't map registers\n"); 123 return; 124 } 125 126 printf("\n"); 127 128 for (i = 0; i < nitems(mvtemp_compat); i++) { 129 if (OF_is_compatible(faa->fa_node, mvtemp_compat[i].compat)) { 130 break; 131 } 132 } 133 KASSERT(i < nitems(mvtemp_compat)); 134 135 mvtemp_compat[i].init(sc); 136 sc->sc_stat_valid = mvtemp_compat[i].stat_valid; 137 sc->sc_calc_temp = mvtemp_compat[i].calc_temp; 138 139 /* Register sensors. */ 140 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 141 sizeof(sc->sc_sensordev.xname)); 142 sc->sc_sensor.type = SENSOR_TEMP; 143 sc->sc_sensor.flags = SENSOR_FINVALID; 144 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor); 145 sensordev_install(&sc->sc_sensordev); 146 sensor_task_register(sc, mvtemp_refresh_sensors, 5); 147 } 148 149 /* AP806 */ 150 151 void 152 mvtemp_ap806_init(struct mvtemp_softc *sc) 153 { 154 } 155 156 int32_t 157 mvtemp_ap806_calc_temp(uint32_t stat) 158 { 159 stat = ((stat & 0x3ff) ^ 0x200) - 0x200; 160 return (stat * 423000) + 150000000 + 273150000; 161 } 162 163 /* CP110 */ 164 165 void 166 mvtemp_cp110_init(struct mvtemp_softc *sc) 167 { 168 uint32_t ctrl; 169 170 ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ctrl_ioh, TEMP_CTRL1); 171 ctrl |= TEMP_CTRL1_TSEN_RESET; 172 bus_space_write_4(sc->sc_iot, sc->sc_ctrl_ioh, TEMP_CTRL1, ctrl); 173 174 ctrl = bus_space_read_4(sc->sc_iot, sc->sc_ctrl_ioh, TEMP_CTRL0); 175 ctrl &= ~TEMP_CTRL0_TSEN_TC_TRIM_MASK; 176 ctrl |= TEMP_CTRL0_TSEN_TC_TRIM_VAL; 177 bus_space_write_4(sc->sc_iot, sc->sc_ctrl_ioh, TEMP_CTRL0, ctrl); 178 } 179 180 int32_t 181 mvtemp_cp110_calc_temp(uint32_t stat) 182 { 183 return ((stat & 0x3ff) * 476100) - 279100000 + 273150000; 184 } 185 186 void 187 mvtemp_refresh_sensors(void *arg) 188 { 189 struct mvtemp_softc *sc = arg; 190 int32_t stat, temp; 191 192 stat = bus_space_read_4(sc->sc_iot, sc->sc_stat_ioh, TEMP_STAT); 193 temp = sc->sc_calc_temp(stat); 194 sc->sc_sensor.value = temp; 195 if ((stat & sc->sc_stat_valid) && temp >= 0) 196 sc->sc_sensor.flags &= ~SENSOR_FINVALID; 197 else 198 sc->sc_sensor.flags |= SENSOR_FINVALID; 199 } 200