// SPDX-License-Identifier: GPL-2.0-or-later /* tmp401.c * * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com> * Preliminary tmp411 support by: * Gabriel Konat, Sander Leget, Wouter Willems * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de> * * Cleanup and support for TMP431 and TMP432 by Guenter Roeck * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
*/
/* * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. * * Note this IC is in some aspect similar to the LM90, but it has quite a * few differences too, for example the local temp has a higher resolution * and thus has 16 bits registers for its value and limit instead of 8 bits.
*/
/* On TMP432, each status has its own register */ #define TMP432_STATUS_LOCAL BIT(0) #define TMP432_STATUS_REMOTE1 BIT(1) #define TMP432_STATUS_REMOTE2 BIT(2)
switch (attr) { case hwmon_temp_input: case hwmon_temp_min: case hwmon_temp_max: case hwmon_temp_crit: case hwmon_temp_lowest: case hwmon_temp_highest:
reg = TMP401_TEMP_MSB[tmp401_temp_reg_index[attr]][channel];
ret = regmap_read(regmap, reg, ®val); if (ret < 0) return ret;
*val = tmp401_register_to_temp(regval, data->extended_range); break; case hwmon_temp_crit_hyst:
ret = regmap_multi_reg_read(regmap, regs, regvals, 2); if (ret < 0) return ret;
*val = tmp401_register_to_temp(regvals[0], data->extended_range) -
(regvals[1] * 1000); break; case hwmon_temp_fault: case hwmon_temp_min_alarm: case hwmon_temp_max_alarm: case hwmon_temp_crit_alarm:
reg = TMP432_STATUS_REG[tmp401_status_reg_index[attr]];
ret = regmap_read(regmap, reg, ®val); if (ret < 0) return ret;
*val = !!(regval & BIT(channel)); break; default: return -EOPNOTSUPP;
} return 0;
}
staticint tmp401_temp_write(struct device *dev, u32 attr, int channel, long val)
{ struct tmp401_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; unsignedint regval; int reg, ret, temp;
mutex_lock(&data->update_lock); switch (attr) { case hwmon_temp_min: case hwmon_temp_max: case hwmon_temp_crit:
reg = TMP401_TEMP_MSB[tmp401_temp_reg_index[attr]][channel];
regval = tmp401_temp_to_register(val, data->extended_range,
attr == hwmon_temp_crit ? 8 : 4);
ret = regmap_write(regmap, reg, regval); break; case hwmon_temp_crit_hyst: if (data->extended_range)
val = clamp_val(val, -64000, 191000); else
val = clamp_val(val, 0, 127000);
reg = TMP401_TEMP_MSB[3][channel];
ret = regmap_read(regmap, reg, ®val); if (ret < 0) break;
temp = tmp401_register_to_temp(regval, data->extended_range);
val = clamp_val(val, temp - 255000, temp);
regval = ((temp - val) + 500) / 1000;
ret = regmap_write(regmap, TMP401_TEMP_CRIT_HYST, regval); break; default:
ret = -EOPNOTSUPP; break;
}
mutex_unlock(&data->update_lock); return ret;
}
staticint tmp401_chip_read(struct device *dev, u32 attr, int channel, long *val)
{ struct tmp401_data *data = dev_get_drvdata(dev);
u32 regval; int ret;
switch (attr) { case hwmon_chip_update_interval:
ret = regmap_read(data->regmap, TMP401_CONVERSION_RATE, ®val); if (ret < 0) return ret;
*val = (1 << (7 - regval)) * 125; break; case hwmon_chip_temp_reset_history:
*val = 0; break; default: return -EOPNOTSUPP;
}
return 0;
}
staticint tmp401_set_convrate(struct regmap *regmap, long val)
{ int rate;
/* * For valid rates, interval can be calculated as * interval = (1 << (7 - rate)) * 125; * Rounded rate is therefore * rate = 7 - __fls(interval * 4 / (125 * 3)); * Use clamp_val() to avoid overflows, and to ensure valid input * for __fls.
*/
val = clamp_val(val, 125, 16000);
rate = 7 - __fls(val * 4 / (125 * 3)); return regmap_write(regmap, TMP401_CONVERSION_RATE, rate);
}
staticint tmp401_chip_write(struct device *dev, u32 attr, int channel, long val)
{ struct tmp401_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; int err;
mutex_lock(&data->update_lock); switch (attr) { case hwmon_chip_update_interval:
err = tmp401_set_convrate(regmap, val); break; case hwmon_chip_temp_reset_history: if (val != 1) {
err = -EINVAL; break;
} /* * Reset history by writing any value to any of the * minimum/maximum registers (0x30-0x37).
*/
err = regmap_write(regmap, 0x30, 0); break; default:
err = -EOPNOTSUPP; break;
}
mutex_unlock(&data->update_lock);
return err;
}
staticint tmp401_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{ switch (type) { case hwmon_chip: return tmp401_chip_read(dev, attr, channel, val); case hwmon_temp: return tmp401_temp_read(dev, attr, channel, val); default: return -EOPNOTSUPP;
}
}
staticint tmp401_write(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long val)
{ switch (type) { case hwmon_chip: return tmp401_chip_write(dev, attr, channel, val); case hwmon_temp: return tmp401_temp_write(dev, attr, channel, val); default: return -EOPNOTSUPP;
}
}
static umode_t tmp401_is_visible(constvoid *data, enum hwmon_sensor_types type,
u32 attr, int channel)
{ switch (type) { case hwmon_chip: switch (attr) { case hwmon_chip_update_interval: case hwmon_chip_temp_reset_history: return 0644; default: break;
} break; case hwmon_temp: switch (attr) { case hwmon_temp_input: case hwmon_temp_min_alarm: case hwmon_temp_max_alarm: case hwmon_temp_crit_alarm: case hwmon_temp_fault: case hwmon_temp_lowest: case hwmon_temp_highest: return 0444; case hwmon_temp_min: case hwmon_temp_max: case hwmon_temp_crit: case hwmon_temp_crit_hyst: return 0644; default: break;
} break; default: break;
} return 0;
}
if (of_property_read_bool(data->client->dev.of_node, "ti,extended-range-enable")) { /* Enable measurement over extended temperature range */
config |= TMP401_CONFIG_RANGE;
}
if (config != config_orig) {
ret = regmap_write(regmap, TMP401_CONFIG, config); if (ret < 0) return ret;
}
ret = of_property_read_u32(data->client->dev.of_node, "ti,n-factor", &nfactor); if (!ret) { if (data->kind == tmp401) {
dev_err(&data->client->dev, "ti,tmp401 does not support n-factor correction\n"); return -EINVAL;
} if (nfactor < -128 || nfactor > 127) {
dev_err(&data->client->dev, "n-factor is invalid (%d)\n", nfactor); return -EINVAL;
}
ret = regmap_write(regmap, TMP4XX_N_FACTOR_REG, (unsignedint)nfactor); if (ret < 0) return ret;
}
ret = of_property_read_u32(data->client->dev.of_node, "ti,beta-compensation", &val); if (!ret) { if (data->kind == tmp401 || data->kind == tmp411) {
dev_err(&data->client->dev, "ti,tmp401 or ti,tmp411 does not support beta compensation\n"); return -EINVAL;
} if (val > 15) {
dev_err(&data->client->dev, "beta-compensation is invalid (%u)\n", val); return -EINVAL;
}
ret = regmap_write(regmap, TMP43X_BETA_RANGE, val); if (ret < 0) return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.