// SPDX-License-Identifier: GPL-2.0-or-later /* * STTS751 sensor driver * * Copyright (C) 2016-2017 Istituto Italiano di Tecnologia - RBCS - EDL * Robotics, Brain and Cognitive Sciences department * Electronic Design Laboratory * * Written by Andrea Merello <andrea.merello@gmail.com> * * Based on LM95241 driver and LM90 driver
*/
/* * Possible update intervals are (in mS): * 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 62.5, 31.25 * However we are not going to complicate things too much and we stick to the * approx value in mS.
*/ staticconstint stts751_intervals[] = {
16000, 8000, 4000, 2000, 1000, 500, 250, 125, 63, 31
};
struct stts751_priv { struct device *dev; struct i2c_client *client; struct mutex access_lock;
u8 interval; int res; int event_max, event_min; int therm; int hyst; int temp; unsignedlong last_update, last_alert_update;
u8 config; bool min_alert, max_alert, therm_trip; bool data_valid, alert_valid; bool notify_max, notify_min;
};
/* * These functions converts temperature from HW format to integer format and * vice-vers. They are (mostly) taken from lm90 driver. Unit is in mC.
*/ staticint stts751_to_deg(s16 hw_val)
{ return hw_val * 125 / 32;
}
/* * There is a trick here, like in the lm90 driver. We have to read two * registers to get the sensor temperature, but we have to beware a * conversion could occur between the readings. We could use the * one-shot conversion register, but we don't want to do this (disables * hardware monitoring). So the solution used here is to read the high * byte once, then the low byte, then the high byte again. If the new * high byte matches the old one, then we have a valid reading. Else we * have to read the low byte again, and now we believe we have a correct * reading.
*/
integer1 = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_H); if (integer1 < 0) {
dev_dbg(&priv->client->dev, "I2C read failed (temp H). ret: %x\n", integer1); return integer1;
}
staticint stts751_read_reg16(struct stts751_priv *priv, int *temp,
u8 hreg, u8 lreg)
{ int integer, frac;
integer = i2c_smbus_read_byte_data(priv->client, hreg); if (integer < 0) return integer;
frac = i2c_smbus_read_byte_data(priv->client, lreg); if (frac < 0) return frac;
*temp = stts751_to_deg((integer << 8) | frac);
return 0;
}
staticint stts751_read_reg8(struct stts751_priv *priv, int *temp, u8 reg)
{ int integer;
integer = i2c_smbus_read_byte_data(priv->client, reg); if (integer < 0) return integer;
*temp = stts751_to_deg(integer << 8);
return 0;
}
/* * Update alert flags without waiting for cache to expire. We detects alerts * immediately for the sake of the alert handler; we still need to deal with * caching to workaround the fact that alarm flags int the status register, * despite what the datasheet claims, gets always cleared on read.
*/ staticint stts751_update_alert(struct stts751_priv *priv)
{ int ret; bool conv_done; int cache_time = msecs_to_jiffies(stts751_intervals[priv->interval]);
/* * Add another 10% because if we run faster than the HW conversion * rate we will end up in reporting incorrectly alarms.
*/
cache_time += cache_time / 10;
ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_STATUS); if (ret < 0) return ret;
dev_dbg(&priv->client->dev, "status reg %x\n", ret);
conv_done = ret & (STTS751_STATUS_TRIPH | STTS751_STATUS_TRIPL); /* * Reset the cache if the cache time expired, or if we are sure * we have valid data from a device conversion, or if we know * our cache has been never written. * * Note that when the cache has been never written the point is * to correctly initialize the timestamp, rather than clearing * the cache values. * * Note that updating the cache timestamp when we get an alarm flag * is required, otherwise we could incorrectly report alarms to be zero.
*/ if (time_after(jiffies, priv->last_alert_update + cache_time) ||
conv_done || !priv->alert_valid) {
priv->max_alert = false;
priv->min_alert = false;
priv->alert_valid = true;
priv->last_alert_update = jiffies;
dev_dbg(&priv->client->dev, "invalidating alert cache\n");
}
/* HW works in range -64C to +127.937C */
temp = clamp_val(temp, -64000, 127937);
mutex_lock(&priv->access_lock);
ret = stts751_set_temp_reg8(priv, temp, STTS751_REG_TLIM); if (ret) gotoexit;
/* * hysteresis reg is relative to therm, so the HW does not need to be * adjusted, we need to update our local copy only.
*/
priv->hyst = temp - (priv->therm - priv->hyst);
priv->therm = temp;
exit:
mutex_unlock(&priv->access_lock); if (ret) return ret;
mutex_lock(&priv->access_lock); /* HW works in range -64C to +127.937C */
temp = clamp_val(temp, priv->event_min, 127937);
ret = stts751_set_temp_reg16(priv, temp,
STTS751_REG_HLIM_H, STTS751_REG_HLIM_L); if (ret) gotoexit;
dev_dbg(&priv->client->dev, "setting event max %ld", temp);
priv->event_max = temp;
ret = count; exit:
mutex_unlock(&priv->access_lock); return ret;
}
mutex_lock(&priv->access_lock); /* HW works in range -64C to +127.937C */
temp = clamp_val(temp, -64000, priv->event_max);
ret = stts751_set_temp_reg16(priv, temp,
STTS751_REG_LLIM_H, STTS751_REG_LLIM_L); if (ret) gotoexit;
dev_dbg(&priv->client->dev, "setting event min %ld", temp);
priv->event_min = temp;
ret = count; exit:
mutex_unlock(&priv->access_lock); return ret;
}
mutex_lock(&priv->access_lock); if (priv->interval == idx) gotoexit;
/* * In early development stages I've become suspicious about the chip * starting to misbehave if I ever set, even briefly, an invalid * configuration. While I'm not sure this is really needed, be * conservative and set rate/resolution in such an order that avoids * passing through an invalid configuration.
*/
/* speed up: lower the resolution, then modify convrate */ if (priv->interval < idx) {
dev_dbg(&priv->client->dev, "lower resolution, then modify convrate");
priv->interval = idx;
ret = stts751_adjust_resolution(priv); if (ret) gotoexit;
}
ret = i2c_smbus_write_byte_data(priv->client, STTS751_REG_RATE, idx); if (ret) gotoexit; /* slow down: modify convrate, then raise resolution */ if (priv->interval != idx) {
dev_dbg(&priv->client->dev, "modify convrate, then raise resolution");
priv->interval = idx;
ret = stts751_adjust_resolution(priv); if (ret) gotoexit;
}
ret = count; exit:
mutex_unlock(&priv->access_lock);
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -ENODEV;
tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_MAN_ID); if (tmp != ST_MAN_ID) return -ENODEV;
/* lower temperaure registers always have bits 0-3 set to zero */
tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_TEMP_L); if (tmp & 0xf) return -ENODEV;
tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_HLIM_L); if (tmp & 0xf) return -ENODEV;
tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_LLIM_L); if (tmp & 0xf) return -ENODEV;
/* smbus timeout register always have bits 0-7 set to zero */
tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_SMBUS_TO); if (tmp & 0x7f) return -ENODEV;
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.