#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <bus/isa/isavar.h>
#include <sys/systm.h>
#include <sys/sensors.h>
#include "itvar.h"
#if defined(ITDEBUG)
#define DPRINTF(x) do { kprintf x; } while (0)
#else
#define DPRINTF(x)
#endif
#define RFACT_NONE 10000
#define RFACT(x, y) (RFACT_NONE * ((x) + (y)) / (y))
int it_probe(device_t);
int it_attach(device_t);
int it_detach(device_t);
u_int8_t it_readreg(struct it_softc *, int);
void it_writereg(struct it_softc *, int, int);
void it_setup_volt(struct it_softc *, int, int);
void it_setup_temp(struct it_softc *, int, int);
void it_setup_fan(struct it_softc *, int, int);
void it_generic_stemp(struct it_softc *, struct ksensor *);
void it_generic_svolt(struct it_softc *, struct ksensor *);
void it_generic_fanrpm(struct it_softc *, struct ksensor *);
void it_refresh_sensor_data(struct it_softc *);
void it_refresh(void *);
static device_method_t it_methods[] = {
DEVMETHOD(device_probe, it_probe),
DEVMETHOD(device_attach, it_attach),
DEVMETHOD(device_detach, it_detach),
DEVMETHOD_END
};
static driver_t it_driver = {
"it",
it_methods,
sizeof (struct it_softc)
};
static devclass_t it_devclass;
DRIVER_MODULE(it, isa, it_driver, it_devclass, NULL, NULL);
const int it_vrfact[] = {
RFACT_NONE,
RFACT_NONE,
RFACT_NONE,
RFACT(68, 100),
RFACT(30, 10),
RFACT(21, 10),
RFACT(83, 20),
RFACT(68, 100),
RFACT_NONE
};
int
it_probe(device_t dev)
{
struct resource *iores;
int iorid = 0;
bus_space_tag_t iot;
bus_space_handle_t ioh;
u_int8_t cr;
iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &iorid,
0ul, ~0ul, 8, RF_ACTIVE);
if (iores == NULL) {
DPRINTF(("%s: can't map i/o space\n", __func__));
return 1;
}
iot = rman_get_bustag(iores);
ioh = rman_get_bushandle(iores);
bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CHIPID);
cr = bus_space_read_1(iot, ioh, ITC_DATA);
bus_release_resource(dev, SYS_RES_IOPORT, iorid, iores);
DPRINTF(("it: vendor id 0x%x\n", cr));
if (cr != IT_ID_IT87)
return 1;
return 0;
}
int
it_attach(device_t dev)
{
struct it_softc *sc = device_get_softc(dev);
int i;
u_int8_t cr;
sc->sc_dev = dev;
sc->sc_iores = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->sc_iorid,
0ul, ~0ul, 8, RF_ACTIVE);
if (sc->sc_iores == NULL) {
device_printf(dev, "can't map i/o space\n");
return 1;
}
sc->sc_iot = rman_get_bustag(sc->sc_iores);
sc->sc_ioh = rman_get_bushandle(sc->sc_iores);
sc->numsensors = IT_NUM_SENSORS;
it_setup_fan(sc, 0, 3);
it_setup_volt(sc, 3, 9);
it_setup_temp(sc, 12, 3);
sensor_task_register(sc, it_refresh, 5);
cr = it_readreg(sc, ITD_CONFIG);
cr |= 0x01 | 0x08;
it_writereg(sc, ITD_CONFIG, cr);
strlcpy(sc->sensordev.xname, device_get_nameunit(sc->sc_dev),
sizeof(sc->sensordev.xname));
for (i = 0; i < sc->numsensors; ++i)
sensor_attach(&sc->sensordev, &sc->sensors[i]);
sensordev_install(&sc->sensordev);
return 0;
}
int
it_detach(device_t dev)
{
struct it_softc *sc = device_get_softc(dev);
int error;
sensordev_deinstall(&sc->sensordev);
sensor_task_unregister(sc);
error = bus_release_resource(dev, SYS_RES_IOPORT, sc->sc_iorid,
sc->sc_iores);
if (error)
return error;
return 0;
}
u_int8_t
it_readreg(struct it_softc *sc, int reg)
{
bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg);
return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, ITC_DATA));
}
void
it_writereg(struct it_softc *sc, int reg, int val)
{
bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_ADDR, reg);
bus_space_write_1(sc->sc_iot, sc->sc_ioh, ITC_DATA, val);
}
void
it_setup_volt(struct it_softc *sc, int start, int n)
{
int i;
for (i = 0; i < n; ++i) {
sc->sensors[start + i].type = SENSOR_VOLTS_DC;
}
ksnprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc),
"VCORE_A");
ksnprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc),
"VCORE_B");
ksnprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc),
"+3.3V");
ksnprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc),
"+5V");
ksnprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc),
"+12V");
ksnprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc),
"Unused");
ksnprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc),
"-12V");
ksnprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc),
"+5VSB");
ksnprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc),
"VBAT");
}
void
it_setup_temp(struct it_softc *sc, int start, int n)
{
int i;
for (i = 0; i < n; ++i)
sc->sensors[start + i].type = SENSOR_TEMP;
}
void
it_setup_fan(struct it_softc *sc, int start, int n)
{
int i;
for (i = 0; i < n; ++i)
sc->sensors[start + i].type = SENSOR_FANRPM;
}
void
it_generic_stemp(struct it_softc *sc, struct ksensor *sensors)
{
int i, sdata;
for (i = 0; i < 3; i++) {
sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i);
sensors[i].value = sdata * 1000000 + 273150000;
}
}
void
it_generic_svolt(struct it_softc *sc, struct ksensor *sensors)
{
int i, sdata;
for (i = 0; i < 9; i++) {
sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i);
DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
sensors[i].value = (sdata << 4);
if (i == 5 || i == 6)
sensors[i].value = ((sdata << 4) - IT_VREF);
sensors[i].value *= it_vrfact[i];
sensors[i].value /= 10;
if (i == 5 || i == 6)
sensors[i].value += IT_VREF * 1000;
}
}
void
it_generic_fanrpm(struct it_softc *sc, struct ksensor *sensors)
{
int i, sdata, divisor, odivisor, ndivisor;
odivisor = ndivisor = divisor = it_readreg(sc, ITD_FAN);
for (i = 0; i < 3; i++, divisor >>= 3) {
sensors[i].flags &= ~SENSOR_FINVALID;
if ((sdata = it_readreg(sc, ITD_SENSORFANBASE + i)) == 0xff) {
sensors[i].flags |= SENSOR_FINVALID;
if (i == 2)
ndivisor ^= 0x40;
else {
ndivisor &= ~(7 << (i * 3));
ndivisor |= ((divisor + 1) & 7) << (i * 3);
}
} else if (sdata == 0) {
sensors[i].value = 0;
} else {
if (i == 2)
divisor = divisor & 1 ? 3 : 1;
sensors[i].value = 1350000 / (sdata << (divisor & 7));
}
}
if (ndivisor != odivisor)
it_writereg(sc, ITD_FAN, ndivisor);
}
void
it_refresh_sensor_data(struct it_softc *sc)
{
it_generic_stemp(sc, &sc->sensors[12]);
it_generic_svolt(sc, &sc->sensors[3]);
it_generic_fanrpm(sc, &sc->sensors[0]);
}
void
it_refresh(void *arg)
{
struct it_softc *sc = (struct it_softc *)arg;
it_refresh_sensor_data(sc);
}