#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/sensors.h>
#include <dev/i2c/i2cvar.h>
#define LM_MODEL_LM75 1
#define LM_MODEL_LM77 2
#define LM_MODEL_DS1775 3
#define LM_MODEL_LM75A 4
#define LM_MODEL_LM76 5
#define LM_POLLTIME 3
#define LM75_REG_TEMP 0x00
#define LM75_REG_CONFIG 0x01
#define LM75_CONFIG_SHUTDOWN 0x01
#define LM75_CONFIG_CMPINT 0x02
#define LM75_CONFIG_OSPOLARITY 0x04
#define LM75_CONFIG_FAULT_QUEUE_MASK 0x18
#define LM75_CONFIG_FAULT_QUEUE_1 (0 << 3)
#define LM75_CONFIG_FAULT_QUEUE_2 (1 << 3)
#define LM75_CONFIG_FAULT_QUEUE_4 (2 << 3)
#define LM75_CONFIG_FAULT_QUEUE_6 (3 << 3)
#define LM77_CONFIG_INTPOLARITY 0x08
#define LM77_CONFIG_FAULT_QUEUE_4 0x10
#define DS1755_CONFIG_RESOLUTION(i) (9 + (((i) >> 5) & 3))
#define LM75_REG_THYST_SET_POINT 0x02
#define LM75_REG_TOS_SET_POINT 0x03
#define LM77_REG_TLOW 0x04
#define LM77_REG_THIGH 0x05
struct lmtemp_softc {
struct device sc_dev;
i2c_tag_t sc_tag;
int sc_addr;
int sc_model;
int sc_bits;
int sc_ratio;
struct ksensor sc_sensor;
struct ksensordev sc_sensordev;
};
int lmtemp_match(struct device *, void *, void *);
void lmtemp_attach(struct device *, struct device *, void *);
const struct cfattach lmtemp_ca = {
sizeof(struct lmtemp_softc),
lmtemp_match,
lmtemp_attach
};
struct cfdriver lmtemp_cd = {
NULL, "lmtemp", DV_DULL
};
int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, int *);
void lmtemp_refresh_sensor_data(void *);
int
lmtemp_match(struct device *parent, void *match, void *aux)
{
struct i2c_attach_args *ia = aux;
if (strcmp(ia->ia_name, "lm75") == 0 ||
strcmp(ia->ia_name, "lm76") == 0 ||
strcmp(ia->ia_name, "lm77") == 0 ||
strcmp(ia->ia_name, "ds1775") == 0 ||
strcmp(ia->ia_name, "lm75a") == 0)
return (1);
return (0);
}
void
lmtemp_attach(struct device *parent, struct device *self, void *aux)
{
struct lmtemp_softc *sc = (struct lmtemp_softc *)self;
struct i2c_attach_args *ia = aux;
u_int8_t cmd, data;
sc->sc_tag = ia->ia_tag;
sc->sc_addr = ia->ia_addr;
printf(": %s", ia->ia_name);
iic_acquire_bus(sc->sc_tag, 0);
cmd = LM75_REG_CONFIG;
if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
iic_release_bus(sc->sc_tag, 0);
printf(", fails to respond\n");
return;
}
if (data & LM75_CONFIG_SHUTDOWN) {
data &= ~LM75_CONFIG_SHUTDOWN;
if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
printf(", cannot wake up\n");
iic_release_bus(sc->sc_tag, 0);
return;
}
printf(", woken up");
}
iic_release_bus(sc->sc_tag, 0);
sc->sc_model = LM_MODEL_LM75;
sc->sc_bits = 9;
sc->sc_ratio = 500000;
if (strcmp(ia->ia_name, "lm77") == 0) {
sc->sc_model = LM_MODEL_LM77;
sc->sc_bits = 13;
} else if (strcmp(ia->ia_name, "lm76") == 0) {
sc->sc_model = LM_MODEL_LM76;
sc->sc_bits = 13;
sc->sc_ratio = 62500;
} else if (strcmp(ia->ia_name, "ds1775") == 0) {
sc->sc_model = LM_MODEL_DS1775;
} else if (strcmp(ia->ia_name, "lm75a") == 0) {
sc->sc_model = LM_MODEL_LM75A;
}
printf("\n");
strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
sizeof(sc->sc_sensordev.xname));
sc->sc_sensor.type = SENSOR_TEMP;
sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
sensordev_install(&sc->sc_sensordev);
sensor_task_register(sc, lmtemp_refresh_sensor_data, LM_POLLTIME);
}
int
lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, int *valp)
{
u_int8_t cmd = which;
u_int16_t data = 0x0000;
int error;
iic_acquire_bus(sc->sc_tag, 0);
error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
iic_release_bus(sc->sc_tag, 0);
if (error)
return (error);
if (data == 0x0000)
return (1);
*valp = betoh16(data) / (1 << (16 - sc->sc_bits));
return (0);
}
void
lmtemp_refresh_sensor_data(void *aux)
{
struct lmtemp_softc *sc = aux;
int val;
int error;
error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val);
if (error) {
#if 0
printf("%s: unable to read temperature, error = %d\n",
sc->sc_dev.dv_xname, error);
#endif
sc->sc_sensor.flags |= SENSOR_FINVALID;
return;
}
sc->sc_sensor.value = val * sc->sc_ratio + 273150000;
sc->sc_sensor.flags &= ~SENSOR_FINVALID;
}