1 /* 2 * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * 25 * $OpenBSD: it.c,v 1.22 2007/03/22 16:55:31 deraadt Exp $ 26 */ 27 28 #include <sys/param.h> 29 #include <sys/kernel.h> 30 #include <sys/bus.h> 31 #include <sys/module.h> 32 #include <sys/rman.h> 33 34 #include <bus/isa/isavar.h> 35 #include <sys/systm.h> 36 37 #include <sys/sensors.h> 38 39 #include "itvar.h" 40 41 #if defined(ITDEBUG) 42 #define DPRINTF(x) do { kprintf x; } while (0) 43 #else 44 #define DPRINTF(x) 45 #endif 46 47 /* 48 * IT87-compatible chips can typically measure voltages up to 4.096 V. 49 * To measure higher voltages the input is attenuated with (external) 50 * resistors. Negative voltages are measured using a reference 51 * voltage. So we have to convert the sensor values back to real 52 * voltages by applying the appropriate resistor factor. 53 */ 54 #define RFACT_NONE 10000 55 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y)) 56 57 int it_probe(device_t); 58 int it_attach(device_t); 59 int it_detach(device_t); 60 u_int8_t it_readreg(struct it_softc *, int); 61 void it_writereg(struct it_softc *, int, int); 62 void it_setup_volt(struct it_softc *, int, int); 63 void it_setup_temp(struct it_softc *, int, int); 64 void it_setup_fan(struct it_softc *, int, int); 65 66 void it_generic_stemp(struct it_softc *, struct ksensor *); 67 void it_generic_svolt(struct it_softc *, struct ksensor *); 68 void it_generic_fanrpm(struct it_softc *, struct ksensor *); 69 70 void it_refresh_sensor_data(struct it_softc *); 71 void it_refresh(void *); 72 73 static device_method_t it_methods[] = { 74 /* Methods from the device interface */ 75 DEVMETHOD(device_probe, it_probe), 76 DEVMETHOD(device_attach, it_attach), 77 DEVMETHOD(device_detach, it_detach), 78 79 /* Terminate method list */ 80 DEVMETHOD_END 81 }; 82 83 static driver_t it_driver = { 84 "it", 85 it_methods, 86 sizeof (struct it_softc) 87 }; 88 89 static devclass_t it_devclass; 90 91 DRIVER_MODULE(it, isa, it_driver, it_devclass, NULL, NULL); 92 93 94 const int it_vrfact[] = { 95 RFACT_NONE, 96 RFACT_NONE, 97 RFACT_NONE, 98 RFACT(68, 100), 99 RFACT(30, 10), 100 RFACT(21, 10), 101 RFACT(83, 20), 102 RFACT(68, 100), 103 RFACT_NONE 104 }; 105 106 int 107 it_probe(device_t dev) 108 { 109 struct resource *iores; 110 int iorid = 0; 111 bus_space_tag_t iot; 112 bus_space_handle_t ioh; 113 u_int8_t cr; 114 115 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, 116 0ul, ~0ul, 8, RF_ACTIVE); 117 if (iores == NULL) { 118 DPRINTF(("%s: can't map i/o space\n", __func__)); 119 return 1; 120 } 121 iot = rman_get_bustag(iores); 122 ioh = rman_get_bushandle(iores); 123 124 /* Check Vendor ID */ 125 bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CHIPID); 126 cr = bus_space_read_1(iot, ioh, ITC_DATA); 127 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 128 DPRINTF(("it: vendor id 0x%x\n", cr)); 129 if (cr != IT_ID_IT87) 130 return 1; 131 132 return 0; 133 } 134 135 int 136 it_attach(device_t dev) 137 { 138 struct it_softc *sc = device_get_softc(dev); 139 int i; 140 u_int8_t cr; 141 142 sc->sc_dev = dev; 143 sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, 144 0ul, ~0ul, 8, RF_ACTIVE); 145 if (sc->sc_iores == NULL) { 146 device_printf(dev, "can't map i/o space\n"); 147 return 1; 148 } 149 sc->sc_iot = rman_get_bustag(sc->sc_iores); 150 sc->sc_ioh = rman_get_bushandle(sc->sc_iores); 151 152 sc->numsensors = IT_NUM_SENSORS; 153 154 it_setup_fan(sc, 0, 3); 155 it_setup_volt(sc, 3, 9); 156 it_setup_temp(sc, 12, 3); 157 158 sensor_task_register(sc, it_refresh, 5); 159 160 /* Activate monitoring */ 161 cr = it_readreg(sc, ITD_CONFIG); 162 cr |= 0x01 | 0x08; 163 it_writereg(sc, ITD_CONFIG, cr); 164 165 /* Initialize sensors */ 166 strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev), 167 sizeof(sc->sensordev.xname)); 168 for (i = 0; i < sc->numsensors; ++i) 169 sensor_attach(&sc->sensordev, &sc->sensors[i]); 170 sensordev_install(&sc->sensordev); 171 172 return 0; 173 } 174 175 int 176 it_detach(device_t dev) 177 { 178 struct it_softc *sc = device_get_softc(dev); 179 int error; 180 181 sensordev_deinstall(&sc->sensordev); 182 sensor_task_unregister(sc); 183 184 error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid, 185 sc->sc_iores); 186 if (error) 187 return error; 188 189 return 0; 190 } 191 192 u_int8_t 193 it_readreg(struct it_softc *sc, int reg) 194 { 195 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg); 196 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, ITC_DATA)); 197 } 198 199 void 200 it_writereg(struct it_softc *sc, int reg, int val) 201 { 202 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg); 203 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_DATA, val); 204 } 205 206 void 207 it_setup_volt(struct it_softc *sc, int start, int n) 208 { 209 int i; 210 211 for (i = 0; i < n; ++i) { 212 sc->sensors[start + i].type = SENSOR_VOLTS_DC; 213 } 214 215 ksnprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc), 216 "VCORE_A"); 217 ksnprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc), 218 "VCORE_B"); 219 ksnprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc), 220 "+3.3V"); 221 ksnprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc), 222 "+5V"); 223 ksnprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc), 224 "+12V"); 225 ksnprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc), 226 "Unused"); 227 ksnprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc), 228 "-12V"); 229 ksnprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc), 230 "+5VSB"); 231 ksnprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc), 232 "VBAT"); 233 } 234 235 void 236 it_setup_temp(struct it_softc *sc, int start, int n) 237 { 238 int i; 239 240 for (i = 0; i < n; ++i) 241 sc->sensors[start + i].type = SENSOR_TEMP; 242 } 243 244 void 245 it_setup_fan(struct it_softc *sc, int start, int n) 246 { 247 int i; 248 249 for (i = 0; i < n; ++i) 250 sc->sensors[start + i].type = SENSOR_FANRPM; 251 } 252 253 void 254 it_generic_stemp(struct it_softc *sc, struct ksensor *sensors) 255 { 256 int i, sdata; 257 258 for (i = 0; i < 3; i++) { 259 sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i); 260 /* Convert temperature to Fahrenheit degres */ 261 sensors[i].value = sdata * 1000000 + 273150000; 262 } 263 } 264 265 void 266 it_generic_svolt(struct it_softc *sc, struct ksensor *sensors) 267 { 268 int i, sdata; 269 270 for (i = 0; i < 9; i++) { 271 sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i); 272 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 273 /* voltage returned as (mV >> 4) */ 274 sensors[i].value = (sdata << 4); 275 /* these two values are negative and formula is different */ 276 if (i == 5 || i == 6) 277 sensors[i].value = ((sdata << 4) - IT_VREF); 278 /* rfact is (factor * 10^4) */ 279 sensors[i].value *= it_vrfact[i]; 280 /* division by 10 gets us back to uVDC */ 281 sensors[i].value /= 10; 282 if (i == 5 || i == 6) 283 sensors[i].value += IT_VREF * 1000; 284 } 285 } 286 287 void 288 it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors) 289 { 290 int i, sdata, divisor, odivisor, ndivisor; 291 292 odivisor = ndivisor = divisor = it_readreg(sc, ITD_FAN); 293 for (i = 0; i < 3; i++, divisor >>= 3) { 294 sensors[i].flags &= ~SENSOR_FINVALID; 295 if ((sdata = it_readreg(sc, ITD_SENSORFANBASE + i)) == 0xff) { 296 sensors[i].flags |= SENSOR_FINVALID; 297 if (i == 2) 298 ndivisor ^= 0x40; 299 else { 300 ndivisor &= ~(7 << (i * 3)); 301 ndivisor |= ((divisor + 1) & 7) << (i * 3); 302 } 303 } else if (sdata == 0) { 304 sensors[i].value = 0; 305 } else { 306 if (i == 2) 307 divisor = divisor & 1 ? 3 : 1; 308 sensors[i].value = 1350000 / (sdata << (divisor & 7)); 309 } 310 } 311 if (ndivisor != odivisor) 312 it_writereg(sc, ITD_FAN, ndivisor); 313 } 314 315 /* 316 * pre: last read occurred >= 1.5 seconds ago 317 * post: sensors[] current data are the latest from the chip 318 */ 319 void 320 it_refresh_sensor_data(struct it_softc *sc) 321 { 322 /* Refresh our stored data for every sensor */ 323 it_generic_stemp(sc, &sc->sensors[12]); 324 it_generic_svolt(sc, &sc->sensors[3]); 325 it_generic_fanrpm(sc, &sc->sensors[0]); 326 } 327 328 void 329 it_refresh(void *arg) 330 { 331 struct it_softc *sc = (struct it_softc *)arg; 332 333 it_refresh_sensor_data(sc); 334 } 335