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 * $DragonFly: src/sys/dev/powermng/it/it.c,v 1.1 2007/10/02 13:37:38 hasso Exp $ 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/param.h> 31 #include <sys/kernel.h> 32 #include <sys/bus.h> 33 #include <sys/module.h> 34 #include <sys/rman.h> 35 36 #include <bus/isa/isavar.h> 37 #include <sys/systm.h> 38 39 #include <sys/sensors.h> 40 41 #include "itvar.h" 42 43 #if defined(ITDEBUG) 44 #define DPRINTF(x) do { printf x; } while (0) 45 #else 46 #define DPRINTF(x) 47 #endif 48 49 /* 50 * IT87-compatible chips can typically measure voltages up to 4.096 V. 51 * To measure higher voltages the input is attenuated with (external) 52 * resistors. Negative voltages are measured using a reference 53 * voltage. So we have to convert the sensor values back to real 54 * voltages by applying the appropriate resistor factor. 55 */ 56 #define RFACT_NONE 10000 57 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y)) 58 59 int it_probe(struct device *); 60 int it_attach(struct device *); 61 int it_detach(struct device *); 62 u_int8_t it_readreg(struct it_softc *, int); 63 void it_writereg(struct it_softc *, int, int); 64 void it_setup_volt(struct it_softc *, int, int); 65 void it_setup_temp(struct it_softc *, int, int); 66 void it_setup_fan(struct it_softc *, int, int); 67 68 void it_generic_stemp(struct it_softc *, struct ksensor *); 69 void it_generic_svolt(struct it_softc *, struct ksensor *); 70 void it_generic_fanrpm(struct it_softc *, struct ksensor *); 71 72 void it_refresh_sensor_data(struct it_softc *); 73 void it_refresh(void *); 74 75 extern struct cfdriver it_cd; 76 77 static device_method_t it_methods[] = { 78 /* Methods from the device interface */ 79 DEVMETHOD(device_probe, it_probe), 80 DEVMETHOD(device_attach, it_attach), 81 DEVMETHOD(device_detach, it_detach), 82 83 /* Terminate method list */ 84 { 0, 0 } 85 }; 86 87 static driver_t it_driver = { 88 "it", 89 it_methods, 90 sizeof (struct it_softc) 91 }; 92 93 static devclass_t it_devclass; 94 95 DRIVER_MODULE(it, isa, it_driver, it_devclass, NULL, NULL); 96 97 98 const int it_vrfact[] = { 99 RFACT_NONE, 100 RFACT_NONE, 101 RFACT_NONE, 102 RFACT(68, 100), 103 RFACT(30, 10), 104 RFACT(21, 10), 105 RFACT(83, 20), 106 RFACT(68, 100), 107 RFACT_NONE 108 }; 109 110 int 111 it_probe(struct device *dev) 112 { 113 struct resource *iores; 114 int iorid = 0; 115 bus_space_tag_t iot; 116 bus_space_handle_t ioh; 117 u_int8_t cr; 118 119 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid, 120 0ul, ~0ul, 8, RF_ACTIVE); 121 if (iores == NULL) { 122 DPRINTF(("%s: can't map i/o space\n", __func__)); 123 return 1; 124 } 125 iot = rman_get_bustag(iores); 126 ioh = rman_get_bushandle(iores); 127 128 /* Check Vendor ID */ 129 bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CHIPID); 130 cr = bus_space_read_1(iot, ioh, ITC_DATA); 131 bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores); 132 DPRINTF(("it: vendor id 0x%x\n", cr)); 133 if (cr != IT_ID_IT87) 134 return 1; 135 136 return 0; 137 } 138 139 int 140 it_attach(struct device *dev) 141 { 142 struct it_softc *sc = device_get_softc(dev); 143 int i; 144 u_int8_t cr; 145 146 sc->sc_dev = dev; 147 sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid, 148 0ul, ~0ul, 8, RF_ACTIVE); 149 if (sc->sc_iores == NULL) { 150 device_printf(dev, "can't map i/o space\n"); 151 return 1; 152 } 153 sc->sc_iot = rman_get_bustag(sc->sc_iores); 154 sc->sc_ioh = rman_get_bushandle(sc->sc_iores); 155 156 sc->numsensors = IT_NUM_SENSORS; 157 158 it_setup_fan(sc, 0, 3); 159 it_setup_volt(sc, 3, 9); 160 it_setup_temp(sc, 12, 3); 161 162 if (sensor_task_register(sc, it_refresh, 5)) { 163 device_printf(sc->sc_dev, "unable to register update task\n"); 164 return 1; 165 } 166 167 /* Activate monitoring */ 168 cr = it_readreg(sc, ITD_CONFIG); 169 cr |= 0x01 | 0x08; 170 it_writereg(sc, ITD_CONFIG, cr); 171 172 /* Initialize sensors */ 173 strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev), 174 sizeof(sc->sensordev.xname)); 175 for (i = 0; i < sc->numsensors; ++i) 176 sensor_attach(&sc->sensordev, &sc->sensors[i]); 177 sensordev_install(&sc->sensordev); 178 179 return 0; 180 } 181 182 int 183 it_detach(struct device *dev) 184 { 185 struct it_softc *sc = device_get_softc(dev); 186 int error; 187 188 sensordev_deinstall(&sc->sensordev); 189 sensor_task_unregister(sc); 190 191 error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid, 192 sc->sc_iores); 193 if (error) 194 return error; 195 196 return 0; 197 } 198 199 u_int8_t 200 it_readreg(struct it_softc *sc, int reg) 201 { 202 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg); 203 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, ITC_DATA)); 204 } 205 206 void 207 it_writereg(struct it_softc *sc, int reg, int val) 208 { 209 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg); 210 bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_DATA, val); 211 } 212 213 void 214 it_setup_volt(struct it_softc *sc, int start, int n) 215 { 216 int i; 217 218 for (i = 0; i < n; ++i) { 219 sc->sensors[start + i].type = SENSOR_VOLTS_DC; 220 } 221 222 ksnprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc), 223 "VCORE_A"); 224 ksnprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc), 225 "VCORE_B"); 226 ksnprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc), 227 "+3.3V"); 228 ksnprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc), 229 "+5V"); 230 ksnprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc), 231 "+12V"); 232 ksnprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc), 233 "Unused"); 234 ksnprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc), 235 "-12V"); 236 ksnprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc), 237 "+5VSB"); 238 ksnprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc), 239 "VBAT"); 240 } 241 242 void 243 it_setup_temp(struct it_softc *sc, int start, int n) 244 { 245 int i; 246 247 for (i = 0; i < n; ++i) 248 sc->sensors[start + i].type = SENSOR_TEMP; 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 } 259 260 void 261 it_generic_stemp(struct it_softc *sc, struct ksensor *sensors) 262 { 263 int i, sdata; 264 265 for (i = 0; i < 3; i++) { 266 sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i); 267 /* Convert temperature to Fahrenheit degres */ 268 sensors[i].value = sdata * 1000000 + 273150000; 269 } 270 } 271 272 void 273 it_generic_svolt(struct it_softc *sc, struct ksensor *sensors) 274 { 275 int i, sdata; 276 277 for (i = 0; i < 9; i++) { 278 sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i); 279 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 280 /* voltage returned as (mV >> 4) */ 281 sensors[i].value = (sdata << 4); 282 /* these two values are negative and formula is different */ 283 if (i == 5 || i == 6) 284 sensors[i].value = ((sdata << 4) - IT_VREF); 285 /* rfact is (factor * 10^4) */ 286 sensors[i].value *= it_vrfact[i]; 287 /* division by 10 gets us back to uVDC */ 288 sensors[i].value /= 10; 289 if (i == 5 || i == 6) 290 sensors[i].value += IT_VREF * 1000; 291 } 292 } 293 294 void 295 it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors) 296 { 297 int i, sdata, divisor, odivisor, ndivisor; 298 299 odivisor = ndivisor = divisor = it_readreg(sc, ITD_FAN); 300 for (i = 0; i < 3; i++, divisor >>= 3) { 301 sensors[i].flags &= ~SENSOR_FINVALID; 302 if ((sdata = it_readreg(sc, ITD_SENSORFANBASE + i)) == 0xff) { 303 sensors[i].flags |= SENSOR_FINVALID; 304 if (i == 2) 305 ndivisor ^= 0x40; 306 else { 307 ndivisor &= ~(7 << (i * 3)); 308 ndivisor |= ((divisor + 1) & 7) << (i * 3); 309 } 310 } else if (sdata == 0) { 311 sensors[i].value = 0; 312 } else { 313 if (i == 2) 314 divisor = divisor & 1 ? 3 : 1; 315 sensors[i].value = 1350000 / (sdata << (divisor & 7)); 316 } 317 } 318 if (ndivisor != odivisor) 319 it_writereg(sc, ITD_FAN, ndivisor); 320 } 321 322 /* 323 * pre: last read occurred >= 1.5 seconds ago 324 * post: sensors[] current data are the latest from the chip 325 */ 326 void 327 it_refresh_sensor_data(struct it_softc *sc) 328 { 329 /* Refresh our stored data for every sensor */ 330 it_generic_stemp(sc, &sc->sensors[12]); 331 it_generic_svolt(sc, &sc->sensors[3]); 332 it_generic_fanrpm(sc, &sc->sensors[0]); 333 } 334 335 void 336 it_refresh(void *arg) 337 { 338 struct it_softc *sc = (struct it_softc *)arg; 339 340 it_refresh_sensor_data(sc); 341 } 342