1 /* $OpenBSD: it.c,v 1.4 2003/11/05 20:57:10 grange Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/device.h> 31 #include <sys/kernel.h> 32 #include <sys/sensors.h> 33 #include <sys/timeout.h> 34 #include <machine/bus.h> 35 36 #include <dev/isa/isareg.h> 37 #include <dev/isa/isavar.h> 38 39 #include <dev/isa/itvar.h> 40 41 #if defined(ITDEBUG) 42 #define DPRINTF(x) do { printf x; } while (0) 43 #else 44 #define DPRINTF(x) 45 #endif 46 47 int it_match(struct device *, void *, void *); 48 void it_attach(struct device *, struct device *, void *); 49 u_int8_t it_readreg(struct it_softc *, int); 50 void it_writereg(struct it_softc *, int, int); 51 void it_setup_volt(struct it_softc *, int, int); 52 void it_setup_temp(struct it_softc *, int, int); 53 void it_setup_fan(struct it_softc *, int, int); 54 55 void it_generic_stemp(struct it_softc *, struct sensor *); 56 void it_generic_svolt(struct it_softc *, struct sensor *); 57 void it_generic_fanrpm(struct it_softc *, struct sensor *); 58 59 void it_refresh_sensor_data(struct it_softc *); 60 void it_refresh(void *); 61 62 struct cfattach it_ca = { 63 sizeof(struct it_softc), 64 it_match, 65 it_attach 66 }; 67 68 struct cfdriver it_cd = { 69 NULL, "it", DV_DULL 70 }; 71 72 struct timeout it_timeout; 73 74 int 75 it_match(struct device *parent, void *match, void *aux) 76 { 77 bus_space_tag_t iot; 78 bus_space_handle_t ioh; 79 struct isa_attach_args *ia = aux; 80 int iobase; 81 int rv; 82 u_int8_t cr; 83 84 iot = ia->ia_iot; 85 iobase = ia->ipa_io[0].base; 86 87 if (bus_space_map(iot, iobase, 8, 0, &ioh)) { 88 DPRINTF(("%s: can't map i/o space\n", __func__)); 89 return (0); 90 } 91 92 /* Check for some power-on defaults */ 93 bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CONFIG); 94 cr = bus_space_read_1(iot, ioh, ITC_DATA); 95 96 /* The monitoring may have been enabled by BIOS */ 97 if (cr == 0x18 || cr == 0x19) 98 rv = 1; 99 100 DPRINTF(("it: rv = %d, cr = %x\n", rv, cr)); 101 102 bus_space_unmap(iot, ioh, 8); 103 104 if (rv) { 105 ia->ipa_nio = 1; 106 ia->ipa_io[0].length = 8; 107 108 ia->ipa_nmem = 0; 109 ia->ipa_nirq = 0; 110 ia->ipa_ndrq = 0; 111 } 112 113 return (rv); 114 } 115 116 void 117 it_attach(struct device *parent, struct device *self, void *aux) 118 { 119 struct it_softc *sc = (void *)self; 120 int iobase; 121 bus_space_tag_t iot; 122 struct isa_attach_args *ia = aux; 123 int i; 124 u_int8_t cr; 125 extern int nsensors; 126 extern struct sensors_head sensors; 127 128 iobase = ia->ipa_io[0].base; 129 iot = sc->it_iot = ia->ia_iot; 130 131 if (bus_space_map(iot, iobase, 8, 0, &sc->it_ioh)) { 132 printf(": can't map i/o space\n"); 133 return; 134 } 135 136 i = it_readreg(sc, ITD_CHIPID); 137 switch (i) { 138 case IT_ID_IT87: 139 printf(": IT87\n"); 140 break; 141 default: 142 printf(": unknown chip (ID %d)\n", i); 143 break; 144 } 145 146 sc->numsensors = IT_NUM_SENSORS; 147 148 /* Reset chip */ 149 it_writereg(sc, ITD_CONFIG, 0x80); 150 151 it_setup_fan(sc, 0, 3); 152 it_setup_volt(sc, 3, 9); 153 it_setup_temp(sc, 12, 3); 154 155 /* Activate monitoring */ 156 cr = it_readreg(sc, ITD_CONFIG); 157 cr |= 0x01 | 0x08; 158 it_writereg(sc, ITD_CONFIG, cr); 159 160 /* Initialize sensors */ 161 for (i = 0; i < sc->numsensors; ++i) { 162 strlcpy(sc->sensors[i].device, sc->sc_dev.dv_xname, 163 sizeof(sc->sensors[i].device)); 164 sc->sensors[i].num = nsensors++; 165 SLIST_INSERT_HEAD(&sensors, &sc->sensors[i], list); 166 } 167 168 timeout_set(&it_timeout, it_refresh, sc); 169 timeout_add(&it_timeout, (15 * hz) / 10); 170 } 171 172 u_int8_t 173 it_readreg(struct it_softc *sc, int reg) 174 { 175 bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg); 176 return (bus_space_read_1(sc->it_iot, sc->it_ioh, ITC_DATA)); 177 } 178 179 void 180 it_writereg(struct it_softc *sc, int reg, int val) 181 { 182 bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg); 183 bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_DATA, val); 184 } 185 186 void 187 it_setup_volt(struct it_softc *sc, int start, int n) 188 { 189 int i; 190 191 for (i = 0; i < n; ++i) { 192 sc->sensors[start + i].type = SENSOR_VOLTS_DC; 193 } 194 195 sc->sensors[start + 0].rfact = 10000; 196 snprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc), 197 "VCORE_A"); 198 sc->sensors[start + 1].rfact = 10000; 199 snprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc), 200 "VCORE_B"); 201 sc->sensors[start + 2].rfact = 10000; 202 snprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc), 203 "+3.3V"); 204 sc->sensors[start + 3].rfact = (int)(( 16.8 / 10) * 10000); 205 snprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc), 206 "+5V"); 207 sc->sensors[start + 4].rfact = (int)(( 40 / 10) * 10000); 208 snprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc), 209 "+12V"); 210 sc->sensors[start + 5].rfact = (int)(( 31.0 / 10) * 10000); 211 snprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc), 212 "Unused"); 213 sc->sensors[start + 6].rfact = (int)(( 103.0 / 20) * 10000); 214 snprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc), 215 "-12V"); 216 sc->sensors[start + 7].rfact = (int)(( 16.8 / 10) * 10000); 217 snprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc), 218 "+5VSB"); 219 sc->sensors[start + 8].rfact = 10000; 220 snprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc), 221 "VBAT"); 222 223 /* Enable voltage monitoring */ 224 it_writereg(sc, ITD_VOLTENABLE, 0xff); 225 } 226 227 void 228 it_setup_temp(struct it_softc *sc, int start, int n) 229 { 230 int i; 231 232 for (i = 0; i < n; ++i) { 233 sc->sensors[start + i].type = SENSOR_TEMP; 234 snprintf(sc->sensors[start + i].desc, 235 sizeof(sc->sensors[start + i].desc), 236 "Temp%d", i + 1); 237 } 238 239 /* Enable temperature monitoring 240 * bits 7 and 8 are reserved, so we don't change them */ 241 i = it_readreg(sc, ITD_TEMPENABLE) & 0xc0; 242 it_writereg(sc, ITD_TEMPENABLE, i | 0x38); 243 } 244 245 void 246 it_setup_fan(struct it_softc *sc, int start, int n) 247 { 248 int i; 249 250 for (i = 0; i < n; ++i) { 251 sc->sensors[start + i].type = SENSOR_FANRPM; 252 snprintf(sc->sensors[start + i].desc, 253 sizeof(sc->sensors[start + i].desc), 254 "Fan%d", i + 1); 255 } 256 257 /* Enable fan rpm monitoring 258 * bits 4 to 6 are the only interesting bits */ 259 i = it_readreg(sc, ITD_FANENABLE) & 0x8f; 260 it_writereg(sc, ITD_FANENABLE, i | 0x70); 261 } 262 263 void 264 it_generic_stemp(struct it_softc *sc, struct sensor *sensors) 265 { 266 int i, sdata; 267 268 for (i = 0; i < 3; i++) { 269 sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i); 270 /* Convert temperature to Fahrenheit degres */ 271 sensors[i].value = sdata * 1000000 + 273150000; 272 } 273 } 274 275 void 276 it_generic_svolt(struct it_softc *sc, struct sensor *sensors) 277 { 278 int i, sdata; 279 280 for (i = 0; i < 9; i++) { 281 sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i); 282 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 283 /* voltage returned as (mV >> 4) */ 284 sensors[i].value = (sdata << 4); 285 /* rfact is (factor * 10^4) */ 286 sensors[i].value *= sensors[i].rfact; 287 /* these two values are negative and formula is different */ 288 if (i == 5) 289 sensors[i].value -= 290 (int) (21.0 / 10 * IT_VREF * 10000); 291 if (i == 6) 292 sensors[i].value -= 293 (int) (83.0 / 20 * IT_VREF * 10000); 294 /* division by 10 gets us back to uVDC */ 295 sensors[i].value /= 10; 296 297 } 298 } 299 300 void 301 it_generic_fanrpm(struct it_softc *sc, struct sensor *sensors) 302 { 303 int i, sdata, divisor; 304 305 for (i = 0; i < 2; i++) { 306 sdata = it_readreg(sc, ITD_SENSORFANBASE + i); 307 switch (i) { 308 case 2: 309 divisor = 2; 310 case 1: 311 divisor = (it_readreg(sc, 312 ITD_FAN) >> 3) & 0x7; 313 break; 314 default: 315 divisor = it_readreg(sc, ITD_FAN) & 0x7; 316 break; 317 } 318 319 if (sdata == 0xff || sdata == 0) { 320 sensors[i].value = 0; 321 } else { 322 sensors[i].value = 1350000 / (sdata << divisor); 323 } 324 } 325 } 326 327 /* 328 * pre: last read occurred >= 1.5 seconds ago 329 * post: sensors[] current data are the latest from the chip 330 */ 331 void 332 it_refresh_sensor_data(struct it_softc *sc) 333 { 334 /* Refresh our stored data for every sensor */ 335 it_generic_stemp(sc, &sc->sensors[12]); 336 it_generic_svolt(sc, &sc->sensors[3]); 337 it_generic_fanrpm(sc, &sc->sensors[0]); 338 } 339 340 void 341 it_refresh(void *arg) 342 { 343 struct it_softc *sc = (struct it_softc *)arg; 344 345 it_refresh_sensor_data(sc); 346 timeout_add(&it_timeout, (15 * hz) / 10); 347 } 348