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 $
28 #include <sys/param.h>
29 #include <sys/kernel.h>
31 #include <sys/module.h>
34 #include <bus/isa/isavar.h>
35 #include <sys/systm.h>
37 #include <sys/sensors.h>
42 #define DPRINTF(x) do { kprintf x; } while (0)
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.
54 #define RFACT_NONE 10000
55 #define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
57 int it_probe(struct device
*);
58 int it_attach(struct device
*);
59 int it_detach(struct device
*);
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);
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
*);
70 void it_refresh_sensor_data(struct it_softc
*);
71 void it_refresh(void *);
73 extern struct cfdriver it_cd
;
75 static device_method_t it_methods
[] = {
76 /* Methods from the device interface */
77 DEVMETHOD(device_probe
, it_probe
),
78 DEVMETHOD(device_attach
, it_attach
),
79 DEVMETHOD(device_detach
, it_detach
),
81 /* Terminate method list */
85 static driver_t it_driver
= {
88 sizeof (struct it_softc
)
91 static devclass_t it_devclass
;
93 DRIVER_MODULE(it
, isa
, it_driver
, it_devclass
, NULL
, NULL
);
96 const int it_vrfact
[] = {
109 it_probe(struct device
*dev
)
111 struct resource
*iores
;
114 bus_space_handle_t ioh
;
117 iores
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &iorid
,
118 0ul, ~0ul, 8, RF_ACTIVE
);
120 DPRINTF(("%s: can't map i/o space\n", __func__
));
123 iot
= rman_get_bustag(iores
);
124 ioh
= rman_get_bushandle(iores
);
126 /* Check Vendor ID */
127 bus_space_write_1(iot
, ioh
, ITC_ADDR
, ITD_CHIPID
);
128 cr
= bus_space_read_1(iot
, ioh
, ITC_DATA
);
129 bus_release_resource(dev
, SYS_RES_IOPORT
, iorid
, iores
);
130 DPRINTF(("it: vendor id 0x%x\n", cr
));
131 if (cr
!= IT_ID_IT87
)
138 it_attach(struct device
*dev
)
140 struct it_softc
*sc
= device_get_softc(dev
);
145 sc
->sc_iores
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &sc
->sc_iorid
,
146 0ul, ~0ul, 8, RF_ACTIVE
);
147 if (sc
->sc_iores
== NULL
) {
148 device_printf(dev
, "can't map i/o space\n");
151 sc
->sc_iot
= rman_get_bustag(sc
->sc_iores
);
152 sc
->sc_ioh
= rman_get_bushandle(sc
->sc_iores
);
154 sc
->numsensors
= IT_NUM_SENSORS
;
156 it_setup_fan(sc
, 0, 3);
157 it_setup_volt(sc
, 3, 9);
158 it_setup_temp(sc
, 12, 3);
160 if (sensor_task_register(sc
, it_refresh
, 5)) {
161 device_printf(sc
->sc_dev
, "unable to register update task\n");
165 /* Activate monitoring */
166 cr
= it_readreg(sc
, ITD_CONFIG
);
168 it_writereg(sc
, ITD_CONFIG
, cr
);
170 /* Initialize sensors */
171 strlcpy(sc
->sensordev
.xname
, device_get_nameunit(sc
->sc_dev
),
172 sizeof(sc
->sensordev
.xname
));
173 for (i
= 0; i
< sc
->numsensors
; ++i
)
174 sensor_attach(&sc
->sensordev
, &sc
->sensors
[i
]);
175 sensordev_install(&sc
->sensordev
);
181 it_detach(struct device
*dev
)
183 struct it_softc
*sc
= device_get_softc(dev
);
186 sensordev_deinstall(&sc
->sensordev
);
187 sensor_task_unregister(sc
);
189 error
= bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->sc_iorid
,
198 it_readreg(struct it_softc
*sc
, int reg
)
200 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ITC_ADDR
, reg
);
201 return (bus_space_read_1(sc
->sc_iot
, sc
->sc_ioh
, ITC_DATA
));
205 it_writereg(struct it_softc
*sc
, int reg
, int val
)
207 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ITC_ADDR
, reg
);
208 bus_space_write_1(sc
->sc_iot
, sc
->sc_ioh
, ITC_DATA
, val
);
212 it_setup_volt(struct it_softc
*sc
, int start
, int n
)
216 for (i
= 0; i
< n
; ++i
) {
217 sc
->sensors
[start
+ i
].type
= SENSOR_VOLTS_DC
;
220 ksnprintf(sc
->sensors
[start
+ 0].desc
, sizeof(sc
->sensors
[0].desc
),
222 ksnprintf(sc
->sensors
[start
+ 1].desc
, sizeof(sc
->sensors
[1].desc
),
224 ksnprintf(sc
->sensors
[start
+ 2].desc
, sizeof(sc
->sensors
[2].desc
),
226 ksnprintf(sc
->sensors
[start
+ 3].desc
, sizeof(sc
->sensors
[3].desc
),
228 ksnprintf(sc
->sensors
[start
+ 4].desc
, sizeof(sc
->sensors
[4].desc
),
230 ksnprintf(sc
->sensors
[start
+ 5].desc
, sizeof(sc
->sensors
[5].desc
),
232 ksnprintf(sc
->sensors
[start
+ 6].desc
, sizeof(sc
->sensors
[6].desc
),
234 ksnprintf(sc
->sensors
[start
+ 7].desc
, sizeof(sc
->sensors
[7].desc
),
236 ksnprintf(sc
->sensors
[start
+ 8].desc
, sizeof(sc
->sensors
[8].desc
),
241 it_setup_temp(struct it_softc
*sc
, int start
, int n
)
245 for (i
= 0; i
< n
; ++i
)
246 sc
->sensors
[start
+ i
].type
= SENSOR_TEMP
;
250 it_setup_fan(struct it_softc
*sc
, int start
, int n
)
254 for (i
= 0; i
< n
; ++i
)
255 sc
->sensors
[start
+ i
].type
= SENSOR_FANRPM
;
259 it_generic_stemp(struct it_softc
*sc
, struct ksensor
*sensors
)
263 for (i
= 0; i
< 3; i
++) {
264 sdata
= it_readreg(sc
, ITD_SENSORTEMPBASE
+ i
);
265 /* Convert temperature to Fahrenheit degres */
266 sensors
[i
].value
= sdata
* 1000000 + 273150000;
271 it_generic_svolt(struct it_softc
*sc
, struct ksensor
*sensors
)
275 for (i
= 0; i
< 9; i
++) {
276 sdata
= it_readreg(sc
, ITD_SENSORVOLTBASE
+ i
);
277 DPRINTF(("sdata[volt%d] 0x%x\n", i
, sdata
));
278 /* voltage returned as (mV >> 4) */
279 sensors
[i
].value
= (sdata
<< 4);
280 /* these two values are negative and formula is different */
281 if (i
== 5 || i
== 6)
282 sensors
[i
].value
= ((sdata
<< 4) - IT_VREF
);
283 /* rfact is (factor * 10^4) */
284 sensors
[i
].value
*= it_vrfact
[i
];
285 /* division by 10 gets us back to uVDC */
286 sensors
[i
].value
/= 10;
287 if (i
== 5 || i
== 6)
288 sensors
[i
].value
+= IT_VREF
* 1000;
293 it_generic_fanrpm(struct it_softc
*sc
, struct ksensor
*sensors
)
295 int i
, sdata
, divisor
, odivisor
, ndivisor
;
297 odivisor
= ndivisor
= divisor
= it_readreg(sc
, ITD_FAN
);
298 for (i
= 0; i
< 3; i
++, divisor
>>= 3) {
299 sensors
[i
].flags
&= ~SENSOR_FINVALID
;
300 if ((sdata
= it_readreg(sc
, ITD_SENSORFANBASE
+ i
)) == 0xff) {
301 sensors
[i
].flags
|= SENSOR_FINVALID
;
305 ndivisor
&= ~(7 << (i
* 3));
306 ndivisor
|= ((divisor
+ 1) & 7) << (i
* 3);
308 } else if (sdata
== 0) {
309 sensors
[i
].value
= 0;
312 divisor
= divisor
& 1 ? 3 : 1;
313 sensors
[i
].value
= 1350000 / (sdata
<< (divisor
& 7));
316 if (ndivisor
!= odivisor
)
317 it_writereg(sc
, ITD_FAN
, ndivisor
);
321 * pre: last read occurred >= 1.5 seconds ago
322 * post: sensors[] current data are the latest from the chip
325 it_refresh_sensor_data(struct it_softc
*sc
)
327 /* Refresh our stored data for every sensor */
328 it_generic_stemp(sc
, &sc
->sensors
[12]);
329 it_generic_svolt(sc
, &sc
->sensors
[3]);
330 it_generic_fanrpm(sc
, &sc
->sensors
[0]);
334 it_refresh(void *arg
)
336 struct it_softc
*sc
= (struct it_softc
*)arg
;
338 it_refresh_sensor_data(sc
);