@@ -103,7 +103,33 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
{
struct tmp108 *tmp108 = dev_get_drvdata(dev);
unsigned int regval;
- int err, reg;
+ int err, hyst;
+
+ if (type == hwmon_chip) {
+ if (attr == hwmon_chip_update_interval) {
+ err = regmap_read(tmp108->regmap, TMP108_REG_CONF,
+ ®val);
+ if (err < 0)
+ return err;
+ switch (regval & TMP108_CONF_CONVRATE_MASK) {
+ case TMP108_CONVRATE_0P25HZ:
+ default:
+ *temp = 4000;
+ break;
+ case TMP108_CONVRATE_1HZ:
+ *temp = 1000;
+ break;
+ case TMP108_CONVRATE_4HZ:
+ *temp = 250;
+ break;
+ case TMP108_CONVRATE_16HZ:
+ *temp = 63;
+ break;
+ }
+ return 0;
+ }
+ return -EOPNOTSUPP;
+ }
switch (attr) {
case hwmon_temp_input:
@@ -113,23 +139,57 @@ static int tmp108_read(struct device *dev, enum hwmon_sensor_types type,
__func__);
return -EAGAIN;
}
- reg = TMP108_REG_TEMP;
+ err = regmap_read(tmp108->regmap, TMP108_REG_TEMP, ®val);
+ if (err < 0)
+ return err;
+ *temp = tmp108_temp_reg_to_mC(regval);
break;
case hwmon_temp_min:
- reg = TMP108_REG_TLOW;
- break;
case hwmon_temp_max:
- reg = TMP108_REG_THIGH;
+ err = regmap_read(tmp108->regmap, attr == hwmon_temp_min ?
+ TMP108_REG_TLOW : TMP108_REG_THIGH, ®val);
+ if (err < 0)
+ return err;
+ *temp = tmp108_temp_reg_to_mC(regval);
+ break;
+ case hwmon_temp_min_alarm:
+ case hwmon_temp_max_alarm:
+ err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val);
+ if (err < 0)
+ return err;
+ *temp = !!(regval & (attr == hwmon_temp_min_alarm ?
+ TMP108_CONF_FL : TMP108_CONF_FH));
+ break;
+ case hwmon_temp_min_hyst:
+ case hwmon_temp_max_hyst:
+ err = regmap_read(tmp108->regmap, TMP108_REG_CONF, ®val);
+ if (err < 0)
+ return err;
+ switch (regval & TMP108_CONF_HYSTERESIS_MASK) {
+ case TMP108_HYSTERESIS_0C:
+ default:
+ hyst = 0;
+ break;
+ case TMP108_HYSTERESIS_1C:
+ hyst = 1000;
+ break;
+ case TMP108_HYSTERESIS_2C:
+ hyst = 2000;
+ break;
+ case TMP108_HYSTERESIS_4C:
+ hyst = 4000;
+ break;
+ }
+ err = regmap_read(tmp108->regmap, attr == hwmon_temp_min_hyst ?
+ TMP108_REG_TLOW : TMP108_REG_THIGH, ®val);
+ if (err < 0)
+ return err;
+ *temp = tmp108_temp_reg_to_mC(regval) - hyst;
break;
default:
return -EOPNOTSUPP;
}
- err = regmap_read(tmp108->regmap, reg, ®val);
- if (err < 0)
- return err;
- *temp = tmp108_temp_reg_to_mC(regval);
-
return 0;
}
@@ -137,33 +197,76 @@ static int tmp108_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long temp)
{
struct tmp108 *tmp108 = dev_get_drvdata(dev);
- int reg;
+ u32 regval, mask;
+ int err;
+
+ if (type == hwmon_chip) {
+ if (attr == hwmon_chip_update_interval) {
+ if (temp < 156)
+ mask = TMP108_CONVRATE_16HZ;
+ else if (temp < 625)
+ mask = TMP108_CONVRATE_4HZ;
+ else if (temp < 2500)
+ mask = TMP108_CONVRATE_1HZ;
+ else
+ mask = TMP108_CONVRATE_0P25HZ;
+
+ return regmap_update_bits(tmp108->regmap,
+ TMP108_REG_CONF,
+ TMP108_CONF_CONVRATE_MASK,
+ mask);
+ }
+ return -EOPNOTSUPP;
+ }
switch (attr) {
case hwmon_temp_min:
- reg = TMP108_REG_TLOW;
- break;
case hwmon_temp_max:
- reg = TMP108_REG_THIGH;
- break;
+ temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC);
+ return regmap_write(tmp108->regmap,
+ attr == hwmon_temp_min ?
+ TMP108_REG_TLOW : TMP108_REG_THIGH,
+ tmp108_mC_to_temp_reg(temp));
+ case hwmon_temp_min_hyst:
+ /* limit value range to prevent overflow */
+ temp = clamp_val(temp, -300000, 300000);
+ err = regmap_read(tmp108->regmap, TMP108_REG_TLOW, ®val);
+ if (err < 0)
+ return err;
+ temp = tmp108_temp_reg_to_mC(regval) - temp;
+ if (temp < 500)
+ mask = TMP108_HYSTERESIS_0C;
+ else if (temp < 1500)
+ mask = TMP108_HYSTERESIS_1C;
+ else if (temp < 3000)
+ mask = TMP108_HYSTERESIS_2C;
+ else
+ mask = TMP108_HYSTERESIS_4C;
+ return regmap_update_bits(tmp108->regmap, TMP108_REG_CONF,
+ TMP108_CONF_HYSTERESIS_MASK,
+ mask);
default:
return -EOPNOTSUPP;
}
-
- temp = clamp_val(temp, TMP108_TEMP_MIN_MC, TMP108_TEMP_MAX_MC);
- return regmap_write(tmp108->regmap, reg, tmp108_mC_to_temp_reg(temp));
}
static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{
+ if (type == hwmon_chip && attr == hwmon_chip_update_interval)
+ return S_IRUGO | S_IWUSR;
+
if (type != hwmon_temp)
return 0;
switch (attr) {
case hwmon_temp_input:
+ case hwmon_temp_max_hyst:
+ case hwmon_temp_min_alarm:
+ case hwmon_temp_max_alarm:
return S_IRUGO;
case hwmon_temp_min:
+ case hwmon_temp_min_hyst:
case hwmon_temp_max:
return S_IRUGO | S_IWUSR;
default:
@@ -172,7 +275,7 @@ static umode_t tmp108_is_visible(const void *data, enum hwmon_sensor_types type,
}
static u32 tmp108_chip_config[] = {
- HWMON_C_REGISTER_TZ,
+ HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
0
};
@@ -182,7 +285,8 @@ static const struct hwmon_channel_info tmp108_chip = {
};
static u32 tmp108_temp_config[] = {
- HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN,
+ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | HWMON_T_MIN_HYST
+ | HWMON_T_MAX_HYST | HWMON_T_MIN_ALARM | HWMON_T_MAX_ALARM,
0
};