1 /* $OpenBSD: it.c,v 1.2 2003/05/28 19:21:11 grange Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Julien Bordet <zejames@greygats.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 /* Must supply an address */ 85 if (ia->ipa_nio < 1) { 86 DPRINTF(("%s: ipa_nio=%d\n", __func__, ia->ipa_nio)); 87 return (0); 88 } 89 90 iot = ia->ia_iot; 91 iobase = ia->ipa_io[0].base; 92 93 if (bus_space_map(iot, iobase, 8, 0, &ioh)) { 94 DPRINTF(("%s: can't map i/o space\n", __func__)); 95 return (0); 96 } 97 98 /* Check for some power-on defaults */ 99 bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CONFIG); 100 cr = bus_space_read_1(iot, ioh, ITC_DATA); 101 102 /* The monitoring may have been enabled by BIOS */ 103 if (cr == 0x18 || cr == 0x19) 104 rv = 1; 105 106 DPRINTF(("it: rv = %d, cr = %x\n", rv, cr)); 107 108 bus_space_unmap(iot, ioh, 8); 109 110 if (rv) { 111 ia->ipa_nio = 1; 112 ia->ipa_io[0].length = 8; 113 114 ia->ipa_nmem = 0; 115 ia->ipa_nirq = 0; 116 ia->ipa_ndrq = 0; 117 } 118 119 return (rv); 120 } 121 122 void 123 it_attach(struct device *parent, struct device *self, void *aux) 124 { 125 struct it_softc *sc = (void *)self; 126 int iobase; 127 bus_space_tag_t iot; 128 struct isa_attach_args *ia = aux; 129 int i; 130 u_int8_t cr; 131 extern int nsensors; 132 extern struct sensors_head sensors; 133 134 iobase = ia->ipa_io[0].base; 135 iot = sc->it_iot = ia->ia_iot; 136 137 if (bus_space_map(iot, iobase, 8, 0, &sc->it_ioh)) { 138 printf(": can't map i/o space\n"); 139 return; 140 } 141 142 i = it_readreg(sc, ITD_CHIPID); 143 switch (i) { 144 case IT_ID_IT87: 145 printf(": IT87\n"); 146 break; 147 default: 148 printf(": unknown chip (ID %d)\n", i); 149 break; 150 } 151 152 sc->numsensors = IT_NUM_SENSORS; 153 154 /* Reset chip */ 155 it_writereg(sc, ITD_CONFIG, 0x80); 156 157 it_setup_fan(sc, 0, 3); 158 it_setup_volt(sc, 3, 9); 159 it_setup_temp(sc, 12, 3); 160 161 /* Activate monitoring */ 162 cr = it_readreg(sc, ITD_CONFIG); 163 cr |= 0x01 | 0x08; 164 it_writereg(sc, ITD_CONFIG, cr); 165 166 /* Initialize sensors */ 167 for (i = 0; i < sc->numsensors; ++i) { 168 strlcpy(sc->sensors[i].device, sc->sc_dev.dv_xname, 169 sizeof(sc->sensors[i].device)); 170 sc->sensors[i].num = nsensors++; 171 SLIST_INSERT_HEAD(&sensors, &sc->sensors[i], list); 172 } 173 174 timeout_set(&it_timeout, it_refresh, sc); 175 timeout_add(&it_timeout, (15 * hz) / 10); 176 } 177 178 u_int8_t 179 it_readreg(struct it_softc *sc, int reg) 180 { 181 bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg); 182 return (bus_space_read_1(sc->it_iot, sc->it_ioh, ITC_DATA)); 183 } 184 185 void 186 it_writereg(struct it_softc *sc, int reg, int val) 187 { 188 bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg); 189 bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_DATA, val); 190 } 191 192 void 193 it_setup_volt(struct it_softc *sc, int start, int n) 194 { 195 int i; 196 197 for (i = 0; i < n; ++i) { 198 sc->sensors[start + i].type = SENSOR_VOLTS_DC; 199 } 200 201 sc->sensors[start + 0].rfact = 10000; 202 snprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc), 203 "VCORE_A"); 204 sc->sensors[start + 1].rfact = 10000; 205 snprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc), 206 "VCORE_B"); 207 sc->sensors[start + 2].rfact = 10000; 208 snprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc), 209 "+3.3V"); 210 sc->sensors[start + 3].rfact = (int)(( 16.8 / 10) * 10000); 211 snprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc), 212 "+5V"); 213 sc->sensors[start + 4].rfact = (int)(( 40 / 10) * 10000); 214 snprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc), 215 "+12V"); 216 sc->sensors[start + 5].rfact = (int)(( 31.0 / 10) * 10000); 217 snprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc), 218 "Unused"); 219 sc->sensors[start + 6].rfact = (int)(( 103.0 / 20) * 10000); 220 snprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc), 221 "-12V"); 222 sc->sensors[start + 7].rfact = (int)(( 16.8 / 10) * 10000); 223 snprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc), 224 "+5VSB"); 225 sc->sensors[start + 8].rfact = 10000; 226 snprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc), 227 "VBAT"); 228 229 /* Enable voltage monitoring */ 230 it_writereg(sc, ITD_VOLTENABLE, 0xff); 231 } 232 233 void 234 it_setup_temp(struct it_softc *sc, int start, int n) 235 { 236 int i; 237 238 for (i = 0; i < n; ++i) { 239 sc->sensors[start + i].type = SENSOR_TEMP; 240 snprintf(sc->sensors[start + i].desc, 241 sizeof(sc->sensors[start + i].desc), 242 "Temp%d", i + 1); 243 } 244 245 /* Enable temperature monitoring 246 * bits 7 and 8 are reserved, so we don't change them */ 247 i = it_readreg(sc, ITD_TEMPENABLE) & 0xc0; 248 it_writereg(sc, ITD_TEMPENABLE, i | 0x38); 249 } 250 251 void 252 it_setup_fan(struct it_softc *sc, int start, int n) 253 { 254 int i; 255 256 for (i = 0; i < n; ++i) { 257 sc->sensors[start + i].type = SENSOR_FANRPM; 258 snprintf(sc->sensors[start + i].desc, 259 sizeof(sc->sensors[start + i].desc), 260 "Fan%d", i + 1); 261 } 262 263 /* Enable fan rpm monitoring 264 * bits 4 to 6 are the only interesting bits */ 265 i = it_readreg(sc, ITD_FANENABLE) & 0x8f; 266 it_writereg(sc, ITD_FANENABLE, i | 0x70); 267 } 268 269 void 270 it_generic_stemp(struct it_softc *sc, struct sensor *sensors) 271 { 272 int i, sdata; 273 274 for (i = 0; i < 3; i++) { 275 sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i); 276 /* Convert temperature to Fahrenheit degres */ 277 sensors[i].value = sdata * 1000000 + 273150000; 278 } 279 } 280 281 void 282 it_generic_svolt(struct it_softc *sc, struct sensor *sensors) 283 { 284 int i, sdata; 285 286 for (i = 0; i < 9; i++) { 287 sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i); 288 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 289 /* voltage returned as (mV >> 4) */ 290 sensors[i].value = (sdata << 4); 291 /* rfact is (factor * 10^4) */ 292 sensors[i].value *= sensors[i].rfact; 293 /* these two values are negative and formula is different */ 294 if (i == 5) 295 sensors[i].value -= 296 (int) (21.0 / 10 * IT_VREF * 10000); 297 if (i == 6) 298 sensors[i].value -= 299 (int) (83.0 / 20 * IT_VREF * 10000); 300 /* division by 10 gets us back to uVDC */ 301 sensors[i].value /= 10; 302 303 } 304 } 305 306 void 307 it_generic_fanrpm(struct it_softc *sc, struct sensor *sensors) 308 { 309 int i, sdata, divisor; 310 311 for (i = 0; i < 2; i++) { 312 sdata = it_readreg(sc, ITD_SENSORFANBASE + i); 313 switch (i) { 314 case 2: 315 divisor = 2; 316 case 1: 317 divisor = (it_readreg(sc, 318 ITD_FAN) >> 3) & 0x7; 319 break; 320 default: 321 divisor = it_readreg(sc, ITD_FAN) & 0x7; 322 break; 323 } 324 325 if (sdata == 0xff || sdata == 0) { 326 sensors[i].value = 0; 327 } else { 328 sensors[i].value = 1350000 / (sdata << divisor); 329 } 330 } 331 } 332 333 /* 334 * pre: last read occurred >= 1.5 seconds ago 335 * post: sensors[] current data are the latest from the chip 336 */ 337 void 338 it_refresh_sensor_data(struct it_softc *sc) 339 { 340 /* Refresh our stored data for every sensor */ 341 it_generic_stemp(sc, &sc->sensors[12]); 342 it_generic_svolt(sc, &sc->sensors[3]); 343 it_generic_fanrpm(sc, &sc->sensors[0]); 344 } 345 346 void 347 it_refresh(void *arg) 348 { 349 struct it_softc *sc = (struct it_softc *)arg; 350 351 it_refresh_sensor_data(sc); 352 timeout_add(&it_timeout, (15 * hz) / 10); 353 } 354