#include <sys/param.h>
#include <sys/device.h>
#include <sys/sensors.h>
#include <sys/systm.h>
#include <machine/fdt.h>
#include <machine/opal.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/fdt.h>
struct opalsens_softc {
struct device sc_dev;
uint32_t sc_data;
struct ksensor sc_sensor;
struct ksensordev sc_sensordev;
};
int opalsens_match(struct device *, void *, void *);
void opalsens_attach(struct device *, struct device *, void *);
const struct cfattach opalsens_ca = {
sizeof (struct opalsens_softc), opalsens_match, opalsens_attach
};
struct cfdriver opalsens_cd = {
NULL, "opalsens", DV_DULL
};
void opalsens_refresh(void *);
int
opalsens_match(struct device *parent, void *match, void *aux)
{
struct fdt_attach_args *faa = aux;
return OF_is_compatible(faa->fa_node, "ibm,opal-sensor");
}
void
opalsens_attach(struct device *parent, struct device *self, void *aux)
{
struct opalsens_softc *sc = (struct opalsens_softc *)self;
struct fdt_attach_args *faa = aux;
char name[32], type[32], label[32];
sc->sc_data = OF_getpropint(faa->fa_node, "sensor-data", 0);
name[0] = 0;
OF_getprop(faa->fa_node, "name", name, sizeof(name));
name[sizeof(name) - 1] = 0;
printf(": \"%s\"", name);
type[0] = 0;
OF_getprop(faa->fa_node, "sensor-type", type, sizeof(type));
type[sizeof(type) - 1] = 0;
if (strcmp(type, "curr") == 0)
sc->sc_sensor.type = SENSOR_AMPS;
else if (strcmp(type, "energy") == 0)
sc->sc_sensor.type = SENSOR_ENERGY;
else if (strcmp(type, "in") == 0)
sc->sc_sensor.type = SENSOR_VOLTS_DC;
else if (strcmp(type, "power") == 0)
sc->sc_sensor.type = SENSOR_WATTS;
else if (strcmp(type, "temp") == 0)
sc->sc_sensor.type = SENSOR_TEMP;
else {
printf(", unsupported sensor type \"%s\"\n", type);
return;
}
label[0] = 0;
OF_getprop(faa->fa_node, "label", label, sizeof(label));
label[sizeof(label) - 1] = 0;
strlcpy(sc->sc_sensor.desc, label, sizeof(sc->sc_sensor.desc));
printf("\n");
strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
sizeof(sc->sc_sensordev.xname));
sc->sc_sensor.flags = SENSOR_FINVALID;
sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
sensordev_install(&sc->sc_sensordev);
sensor_task_register(sc, opalsens_refresh, 5);
}
void
opalsens_refresh(void *arg)
{
struct opalsens_softc *sc = arg;
uint64_t value;
int64_t error;
error = opal_sensor_read_u64(sc->sc_data, 0, opal_phys(&value));
if (error == OPAL_SUCCESS)
sc->sc_sensor.flags &= ~SENSOR_FINVALID;
else
sc->sc_sensor.flags |= SENSOR_FINVALID;
switch (sc->sc_sensor.type) {
case SENSOR_AMPS:
case SENSOR_VOLTS_DC:
sc->sc_sensor.value = value * 1000;
break;
case SENSOR_WATTS:
sc->sc_sensor.value = value * 1000000;
break;
case SENSOR_TEMP:
if (value == 0)
sc->sc_sensor.flags |= SENSOR_FINVALID;
else
sc->sc_sensor.value = 273150000 + value * 1000000;
break;
default:
sc->sc_sensor.value = value;
break;
}
}