2 * Copyright (c) 2003 Julien Bordet <zejames@greyhats.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
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 $
29 #include <sys/cdefs.h>
30 #include <sys/param.h>
31 #include <sys/kernel.h>
33 #include <sys/module.h>
36 #include <bus/isa/isavar.h>
37 #include <sys/systm.h>
39 #include <sys/sensors.h>
44 #define DPRINTF(x) do { printf x; } while (0)
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.
56 #define RFACT_NONE 10000
57 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
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);
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 *);
72 void it_refresh_sensor_data(struct it_softc *);
73 void it_refresh(void *);
75 extern struct cfdriver it_cd;
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),
83 /* Terminate method list */
87 static driver_t it_driver = {
90 sizeof (struct it_softc)
93 static devclass_t it_devclass;
95 DRIVER_MODULE(it, isa, it_driver, it_devclass, NULL, NULL);
98 const int it_vrfact[] = {
111 it_probe(struct device *dev)
113 struct resource *iores;
116 bus_space_handle_t ioh;
119 iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
120 0ul, ~0ul, 8, RF_ACTIVE);
122 DPRINTF(("%s: can't map i/o space\n", __func__));
125 iot = rman_get_bustag(iores);
126 ioh = rman_get_bushandle(iores);
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)
140 it_attach(struct device *dev)
142 struct it_softc *sc = device_get_softc(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");
153 sc->sc_iot = rman_get_bustag(sc->sc_iores);
154 sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
156 sc->numsensors = IT_NUM_SENSORS;
158 it_setup_fan(sc, 0, 3);
159 it_setup_volt(sc, 3, 9);
160 it_setup_temp(sc, 12, 3);
162 if (sensor_task_register(sc, it_refresh, 5)) {
163 device_printf(sc->sc_dev, "unable to register update task\n");
167 /* Activate monitoring */
168 cr = it_readreg(sc, ITD_CONFIG);
170 it_writereg(sc, ITD_CONFIG, cr);
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);
183 it_detach(struct device *dev)
185 struct it_softc *sc = device_get_softc(dev);
188 sensordev_deinstall(&sc->sensordev);
189 sensor_task_unregister(sc);
191 error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
200 it_readreg(struct it_softc *sc, int reg)
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));
207 it_writereg(struct it_softc *sc, int reg, int val)
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);
214 it_setup_volt(struct it_softc *sc, int start, int n)
218 for (i = 0; i < n; ++i) {
219 sc->sensors[start + i].type = SENSOR_VOLTS_DC;
222 ksnprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc),
224 ksnprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc),
226 ksnprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc),
228 ksnprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc),
230 ksnprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc),
232 ksnprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc),
234 ksnprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc),
236 ksnprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc),
238 ksnprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc),
243 it_setup_temp(struct it_softc *sc, int start, int n)
247 for (i = 0; i < n; ++i)
248 sc->sensors[start + i].type = SENSOR_TEMP;
252 it_setup_fan(struct it_softc *sc, int start, int n)
256 for (i = 0; i < n; ++i)
257 sc->sensors[start + i].type = SENSOR_FANRPM;
261 it_generic_stemp(struct it_softc *sc, struct ksensor *sensors)
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;
273 it_generic_svolt(struct it_softc *sc, struct ksensor *sensors)
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;
295 it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors)
297 int i, sdata, divisor, odivisor, ndivisor;
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;
307 ndivisor &= ~(7 << (i * 3));
308 ndivisor |= ((divisor + 1) & 7) << (i * 3);
310 } else if (sdata == 0) {
311 sensors[i].value = 0;
314 divisor = divisor & 1 ? 3 : 1;
315 sensors[i].value = 1350000 / (sdata << (divisor & 7));
318 if (ndivisor != odivisor)
319 it_writereg(sc, ITD_FAN, ndivisor);
323 * pre: last read occurred >= 1.5 seconds ago
324 * post: sensors[] current data are the latest from the chip
327 it_refresh_sensor_data(struct it_softc *sc)
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]);
336 it_refresh(void *arg)
338 struct it_softc *sc = (struct it_softc *)arg;
340 it_refresh_sensor_data(sc);