Index: sys/dev/iicbus/tmp461.c =================================================================== --- sys/dev/iicbus/tmp461.c +++ sys/dev/iicbus/tmp461.c @@ -44,94 +44,147 @@ #include #include -#define BIT(x) (1UL << (x)) +#define BIT(x) (1UL << (x)) + +/* register map */ +#define LOCAL_TEMP_REG_MSB 0x0 +#define LOCAL_TEMP_REG_LSB 0x15 +#define REMOTE_TEMP_REG_MSB 0x1 +#define REMOTE_TEMP_REG_LSB 0x10 +#define STATUS_REG 0x2 +#define STATUS_REG_TEMP_LOCAL BIT(2) +#define CONFIG_REG_R 0x3 +#define CONFIG_REG_W 0x9 +#define CONFIG_REG_TEMP_RANGE_BIT BIT(2) +#define CONFIG_REG_STANDBY_BIT BIT(6) +#define CONVERSION_RATE_REG 0x4 +#define ONESHOT_REG 0xF +#define EXTENDED_MODE_TEMP_OFFSET 64 -#define TMP461_LOCAL_TEMP_REG_MSB 0x0 -#define TMP461_LOCAL_TEMP_REG_LSB 0x15 -#define TMP461_GLOBAL_TEMP_REG_MSB 0x1 -#define TMP461_GLOBAL_TEMP_REG_LSB 0x10 -#define TMP461_CONFIG_REG 0x3 -#define TMP461_CONFIG_REG_TEMP_RANGE_BIT BIT(2) - -#define TMP461_EXTENDED_TEMP_MODIFIER 64 /* 28.4 fixed point representation of 273.15f */ -#define TMP461_C_TO_K_FIX 4370 -#define TMP461_TEMP_LSB 0 +#define TEMP_C_TO_K_FIX 4370 + +#define SENSOR_MAX_CONV_TIME 16000000 +#define LOCAL_MEASURE 0 +#define REMOTE_MEASURE 1 + +/* flags */ +#define LOCAL_TEMP_DOUBLE_REG BIT(0) +#define REMOTE_TEMP_DOUBLE_REG BIT(1) -static int tmp461_probe(device_t dev); -static int tmp461_attach(device_t dev); -static int tmp461_read_1(device_t dev, uint8_t reg, uint8_t *data); -static int tmp461_read_temp(device_t dev, int32_t *temp); -static int tmp461_detach(device_t dev); -static int tmp461_sensor_sysctl(SYSCTL_HANDLER_ARGS); +static int temp_sensor_probe(device_t dev); +static int temp_sensor_attach(device_t dev); +static int temp_sensor_read_1(device_t dev, uint8_t reg, uint8_t *data); +static int temp_sensor_write_1(device_t dev, uint8_t reg, uint8_t data); +static int temp_sensor_read_temp(device_t dev, int32_t *temp, bool mode); +static int temp_sensor_detach(device_t dev); +static int temp_sensor_sysctl(SYSCTL_HANDLER_ARGS); -static device_method_t tmp461_methods[] = { - DEVMETHOD(device_probe, tmp461_probe), - DEVMETHOD(device_attach, tmp461_attach), - DEVMETHOD(device_detach, tmp461_detach), +static device_method_t temp_sensor_methods[] = { + DEVMETHOD(device_probe, temp_sensor_probe), + DEVMETHOD(device_attach, temp_sensor_attach), + DEVMETHOD(device_detach, temp_sensor_detach), DEVMETHOD_END }; -static driver_t tmp461_driver = { - "tmp461_dev", - tmp461_methods, +static driver_t temp_sensor_driver = { + "temp_sensor_dev", + temp_sensor_methods, 0 }; -static struct ofw_compat_data tmp461_compat_data[] = { - { "ti,tmp461", 1 }, - { NULL, 0 } +struct sensor_data { + const char *name; + const char *desc; + uint8_t flags; }; -DRIVER_MODULE(tmp461, iicbus, tmp461_driver, 0, 0); -IICBUS_FDT_PNP_INFO(tmp461_compat_data); +static struct sensor_data sensor_list[] = { + {"adt7461", "ADT7461 Thernal Sensor Information", + REMOTE_TEMP_DOUBLE_REG}, + {"tmp461", "TMP461 Thernal Sensor Information", + LOCAL_TEMP_DOUBLE_REG | REMOTE_TEMP_DOUBLE_REG} +}; + +static struct ofw_compat_data device_compat_data[] = { + {"adi,adt7461", (uintptr_t)&sensor_list[0]}, + {"ti,tmp461", (uintptr_t)&sensor_list[1]}, + {NULL, 0} +}; + +DRIVER_MODULE(generic_thermal_sensor_driver, iicbus, temp_sensor_driver, 0, 0); +IICBUS_FDT_PNP_INFO(device_compat_data); static int -tmp461_attach(device_t dev) +temp_sensor_attach(device_t dev) { struct sysctl_oid *sensor_root_oid; + struct sensor_data *local_dev; struct sysctl_ctx_list *ctx; + uint8_t data; + local_dev = (struct sensor_data *) + ofw_bus_search_compatible(dev, device_compat_data)->ocd_data; ctx = device_get_sysctl_ctx(dev); - + sensor_root_oid = SYSCTL_ADD_NODE(ctx, SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, "temperature", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, - "TMP 461 Thermal Sensor Information"); + "Thermal Sensor Information"); if (sensor_root_oid == NULL) return (ENXIO); SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensor_root_oid), OID_AUTO, - "tmp461", CTLTYPE_INT | CTLFLAG_RD, dev, 0, - tmp461_sensor_sysctl, "IK0", "TMP461 Thermal Sensor"); + "local_sensor", CTLTYPE_INT | CTLFLAG_RD, dev, + LOCAL_MEASURE, temp_sensor_sysctl, "IK1", local_dev->desc); + + /* get status register */ + if (temp_sensor_read_1(dev, STATUS_REG, &data) != 0) + return (ENXIO); + + if (!(data & STATUS_REG_TEMP_LOCAL)) + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(sensor_root_oid), OID_AUTO, + "remote_sensor", CTLTYPE_INT | CTLFLAG_RD, dev, + REMOTE_MEASURE, temp_sensor_sysctl, "IK1", local_dev->desc); + + /* set standby mode */ + if (temp_sensor_read_1(dev, CONFIG_REG_R, &data) != 0) + return (ENXIO); + + data |= CONFIG_REG_STANDBY_BIT; + if (temp_sensor_write_1(dev, CONFIG_REG_W, data) != 0) + return (ENXIO); return (0); } static int -tmp461_probe(device_t dev) +temp_sensor_probe(device_t dev) { + struct sensor_data *local_dev; if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_search_compatible(dev, tmp461_compat_data)->ocd_data) + local_dev = (struct sensor_data *) + ofw_bus_search_compatible(dev, device_compat_data)->ocd_data; + if (!local_dev) return (ENXIO); - device_set_desc(dev, "TMP461 Thermal Sensor"); + device_set_desc(dev, local_dev->name); return (BUS_PROBE_GENERIC); } static int -tmp461_detach(device_t dev) +temp_sensor_detach(device_t dev) { return (0); } static int -tmp461_read_1(device_t dev, uint8_t reg, uint8_t *data) +temp_sensor_read_1(device_t dev, uint8_t reg, uint8_t *data) { int error; @@ -143,49 +196,99 @@ } static int -tmp461_read_temp(device_t dev, int32_t *temp) +temp_sensor_write_1(device_t dev, uint8_t reg, uint8_t data) { - bool extended_mode; - uint8_t data; int error; - /* read temperature range */ - error = tmp461_read_1(dev, TMP461_CONFIG_REG, &data); + error = iicdev_writeto(dev, reg, (void *) &data, 1, IIC_WAIT); if (error != 0) - return (ENXIO); + device_printf(dev, "Failed to write to device\n"); - extended_mode = data & TMP461_CONFIG_REG_TEMP_RANGE_BIT; + return (error); +} + +static int +temp_sensor_read_temp(device_t dev, int32_t *temp, bool remote_measure) +{ + struct sensor_data *local_dev; + uint8_t data, offset; + int error; + + local_dev = (struct sensor_data *) + ofw_bus_search_compatible(dev, device_compat_data)->ocd_data; + + error = temp_sensor_read_1(dev, CONVERSION_RATE_REG, &data); + if (error != 0) + return (ENXIO); - /* read temp MSB */ - error = tmp461_read_1(dev, TMP461_LOCAL_TEMP_REG_MSB, &data); + /* trigger sample*/ + error = temp_sensor_write_1(dev, ONESHOT_REG, 0xFF); if (error != 0) return (ENXIO); - *temp = signed_extend32(data, TMP461_TEMP_LSB, 8) - - (extended_mode ? TMP461_EXTENDED_TEMP_MODIFIER : 0); + /* wait for conversion time */ + DELAY(SENSOR_MAX_CONV_TIME/(1UL<> 4)) + TMP461_C_TO_K_FIX) >> 4; + offset = (data & CONFIG_REG_TEMP_RANGE_BIT ? + EXTENDED_MODE_TEMP_OFFSET : 0); + + if (remote_measure == LOCAL_MEASURE) { + error = temp_sensor_read_1(dev, LOCAL_TEMP_REG_MSB, &data); + if (error != 0) + return (ENXIO); + + data -= offset; + *temp = signed_extend32(data, 0, 8) << 4; + + if (local_dev->flags & LOCAL_TEMP_DOUBLE_REG) { + error = temp_sensor_read_1(dev, + LOCAL_TEMP_REG_LSB, &data); + if (error != 0) + return (ENXIO); + + *temp |= data >> 4; + } + } else { + error = temp_sensor_read_1(dev, REMOTE_TEMP_REG_MSB, &data); + if (error != 0) + return (ENXIO); + + data -= offset; + *temp = signed_extend32(data, 0, 8) << 4; + + if (local_dev->flags & REMOTE_TEMP_DOUBLE_REG) { + error = temp_sensor_read_1(dev, + REMOTE_TEMP_REG_LSB, &data); + if (error != 0) + return (ENXIO); + + *temp |= data >> 4; + } + } + *temp = (((*temp + TEMP_C_TO_K_FIX) * 10) >> 4); return (0); } static int -tmp461_sensor_sysctl(SYSCTL_HANDLER_ARGS) +temp_sensor_sysctl(SYSCTL_HANDLER_ARGS) { device_t dev; int32_t temp; int error; + bool mode; dev = arg1; + mode = arg2; - error = tmp461_read_temp(dev, &temp); + error = temp_sensor_read_temp(dev, &temp, mode); if (error != 0) return (error); return (sysctl_handle_int(oidp, &temp, 0, req)); } -