powermng: Fix some printf -> kprintf.
[dragonfly.git] / sys / dev / powermng / it / it.c
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(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);
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 extern struct cfdriver it_cd;
74
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),
80
81         /* Terminate method list */
82         { 0, 0 }
83 };
84
85 static driver_t it_driver = {
86         "it",
87         it_methods,
88         sizeof (struct it_softc)
89 };
90
91 static devclass_t it_devclass;
92
93 DRIVER_MODULE(it, isa, it_driver, it_devclass, NULL, NULL);
94
95
96 const int it_vrfact[] = {
97         RFACT_NONE,
98         RFACT_NONE,
99         RFACT_NONE,
100         RFACT(68, 100),
101         RFACT(30, 10),
102         RFACT(21, 10),
103         RFACT(83, 20),
104         RFACT(68, 100),
105         RFACT_NONE
106 };
107
108 int
109 it_probe(struct device *dev)
110 {
111         struct resource *iores;
112         int iorid = 0;
113         bus_space_tag_t iot;
114         bus_space_handle_t ioh;
115         u_int8_t cr;
116
117         iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
118             0ul, ~0ul, 8, RF_ACTIVE);
119         if (iores == NULL) {
120                 DPRINTF(("%s: can't map i/o space\n", __func__));
121                 return 1;
122         }
123         iot = rman_get_bustag(iores);
124         ioh = rman_get_bushandle(iores);
125
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)
132                 return 1;
133
134         return 0;
135 }
136
137 int
138 it_attach(struct device *dev)
139 {
140         struct it_softc *sc = device_get_softc(dev);
141         int i;
142         u_int8_t cr;
143
144         sc->sc_dev = 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");
149                 return 1;
150         }
151         sc->sc_iot = rman_get_bustag(sc->sc_iores);
152         sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
153
154         sc->numsensors = IT_NUM_SENSORS;
155
156         it_setup_fan(sc, 0, 3);
157         it_setup_volt(sc, 3, 9);
158         it_setup_temp(sc, 12, 3);
159
160         if (sensor_task_register(sc, it_refresh, 5)) {
161                 device_printf(sc->sc_dev, "unable to register update task\n");
162                 return 1;
163         }
164
165         /* Activate monitoring */
166         cr = it_readreg(sc, ITD_CONFIG);
167         cr |= 0x01 | 0x08;
168         it_writereg(sc, ITD_CONFIG, cr);
169
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);
176
177         return 0;
178 }
179
180 int
181 it_detach(struct device *dev)
182 {
183         struct it_softc *sc = device_get_softc(dev);
184         int error;
185
186         sensordev_deinstall(&sc->sensordev);
187         sensor_task_unregister(sc);
188
189         error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
190             sc->sc_iores);
191         if (error)
192                 return error;
193
194         return 0;
195 }
196
197 u_int8_t
198 it_readreg(struct it_softc *sc, int reg)
199 {
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));
202 }
203
204 void
205 it_writereg(struct it_softc *sc, int reg, int val)
206 {
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);
209 }
210
211 void
212 it_setup_volt(struct it_softc *sc, int start, int n)
213 {
214         int i;
215
216         for (i = 0; i < n; ++i) {
217                 sc->sensors[start + i].type = SENSOR_VOLTS_DC;
218         }
219
220         ksnprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc),
221             "VCORE_A");
222         ksnprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc),
223             "VCORE_B");
224         ksnprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc),
225             "+3.3V");
226         ksnprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc),
227             "+5V");
228         ksnprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc),
229             "+12V");
230         ksnprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc),
231             "Unused");
232         ksnprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc),
233             "-12V");
234         ksnprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc),
235             "+5VSB");
236         ksnprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc),
237             "VBAT");
238 }
239
240 void
241 it_setup_temp(struct it_softc *sc, int start, int n)
242 {
243         int i;
244
245         for (i = 0; i < n; ++i)
246                 sc->sensors[start + i].type = SENSOR_TEMP;
247 }
248
249 void
250 it_setup_fan(struct it_softc *sc, int start, int n)
251 {
252         int i;
253
254         for (i = 0; i < n; ++i)
255                 sc->sensors[start + i].type = SENSOR_FANRPM;
256 }
257
258 void
259 it_generic_stemp(struct it_softc *sc, struct ksensor *sensors)
260 {
261         int i, sdata;
262
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;
267         }
268 }
269
270 void
271 it_generic_svolt(struct it_softc *sc, struct ksensor *sensors)
272 {
273         int i, sdata;
274
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;
289         }
290 }
291
292 void
293 it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors)
294 {
295         int i, sdata, divisor, odivisor, ndivisor;
296
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;
302                         if (i == 2)
303                                 ndivisor ^= 0x40;
304                         else {
305                                 ndivisor &= ~(7 << (i * 3));
306                                 ndivisor |= ((divisor + 1) & 7) << (i * 3);
307                         }
308                 } else if (sdata == 0) {
309                         sensors[i].value = 0;
310                 } else {
311                         if (i == 2)
312                                 divisor = divisor & 1 ? 3 : 1;
313                         sensors[i].value = 1350000 / (sdata << (divisor & 7));
314                 }
315         }
316         if (ndivisor != odivisor)
317                 it_writereg(sc, ITD_FAN, ndivisor);
318 }
319
320 /*
321  * pre:  last read occurred >= 1.5 seconds ago
322  * post: sensors[] current data are the latest from the chip
323  */
324 void
325 it_refresh_sensor_data(struct it_softc *sc)
326 {
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]);
331 }
332
333 void
334 it_refresh(void *arg)
335 {
336         struct it_softc *sc = (struct it_softc *)arg;
337
338         it_refresh_sensor_data(sc);
339 }