mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
hwmon: (sht4x) Add support for Sensirion STS4x temperature sensors
The Sensirion STS4x series is the temperature-only variant of the SHT4x family. It shares the same I2C command set, conversion formulas, CRC checksum, and timing with the SHT4x, but only returns temperature data (3 bytes: 2 data bytes + 1 CRC byte). Add support for the STS4x series by dynamically adjusting the read response length, suppressing humidity channel attributes when probed as STS4x, and omitting heater sysfs attributes. Link: https://sensirion.com/resource/datasheet/sts4x Signed-off-by: Alessandro Zini <alessandro.zini@siemens.com> Link: https://patch.msgid.link/20260821091924.18975-3-alessandro.zini@siemens.com Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
961fa6fa65
commit
e9e597193e
|
|
@ -15,6 +15,16 @@ Supported Chips:
|
|||
|
||||
English: https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/2_Humidity_Sensors/Datasheets/Sensirion_Humidity_Sensors_SHT4x_Datasheet.pdf
|
||||
|
||||
* Sensirion STS4X
|
||||
|
||||
Prefix: 'sts4x'
|
||||
|
||||
Addresses scanned: None
|
||||
|
||||
Datasheet:
|
||||
|
||||
English: https://sensirion.com/resource/datasheet/sts4x
|
||||
|
||||
Author: Navin Sankar Velliangiri <navin@linumiz.com>
|
||||
|
||||
|
||||
|
|
@ -22,9 +32,10 @@ Description
|
|||
-----------
|
||||
|
||||
This driver implements support for the Sensirion SHT4x chip, a humidity
|
||||
and temperature sensor. Temperature is measured in degree celsius, relative
|
||||
humidity is expressed as a percentage. In sysfs interface, all values are
|
||||
scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500.
|
||||
and temperature sensor, and the Sensirion STS4x chip, a temperature sensor.
|
||||
Temperature is measured in degree celsius, relative humidity is expressed as a
|
||||
percentage (on SHT4x only). In sysfs interface, all values are scaled by 1000,
|
||||
i.e. the value for 31.5 degrees celsius is 31500.
|
||||
|
||||
Usage Notes
|
||||
-----------
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#define SHT4X_CRC8_LEN 1
|
||||
#define SHT4X_WORD_LEN 2
|
||||
#define SHT4X_RESPONSE_LENGTH 6
|
||||
#define STS4X_RESPONSE_LENGTH 3
|
||||
#define SHT4X_CRC8_POLYNOMIAL 0x31
|
||||
#define SHT4X_CRC8_INIT 0xff
|
||||
#define SHT4X_MIN_TEMPERATURE -45000
|
||||
|
|
@ -52,9 +53,15 @@
|
|||
|
||||
DECLARE_CRC8_TABLE(sht4x_crc8_table);
|
||||
|
||||
enum sht4x_chips {
|
||||
sht4x,
|
||||
sts4x,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sht4x_data - All the data required to operate an SHT4X chip
|
||||
* @client: the i2c client associated with the SHT4X
|
||||
* @chip_id: the chip type (sht4x or sts4x)
|
||||
* @heating_complete: the time that the last heating finished
|
||||
* @data_pending: true if and only if there are measurements to retrieve after heating
|
||||
* @heater_power: the power at which the heater will be started
|
||||
|
|
@ -67,6 +74,7 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table);
|
|||
*/
|
||||
struct sht4x_data {
|
||||
struct i2c_client *client;
|
||||
enum sht4x_chips chip_id;
|
||||
u64 heating_complete; /* in jiffies */
|
||||
bool data_pending;
|
||||
u32 heater_power; /* in milli-watts */
|
||||
|
|
@ -92,11 +100,15 @@ static int sht4x_read_values(struct sht4x_data *data)
|
|||
u8 crc;
|
||||
u8 cmd[SHT4X_CMD_LEN] = {SHT4X_CMD_MEASURE_HPM};
|
||||
u8 raw_data[SHT4X_RESPONSE_LENGTH];
|
||||
u64 curr_jiffies;
|
||||
size_t response_length = data->chip_id == sts4x ?
|
||||
STS4X_RESPONSE_LENGTH : SHT4X_RESPONSE_LENGTH;
|
||||
|
||||
curr_jiffies = get_jiffies_64();
|
||||
if (time_before64(curr_jiffies, data->heating_complete))
|
||||
msleep(jiffies_to_msecs(data->heating_complete - curr_jiffies));
|
||||
if (data->chip_id != sts4x) {
|
||||
u64 curr_jiffies = get_jiffies_64();
|
||||
|
||||
if (time_before64(curr_jiffies, data->heating_complete))
|
||||
msleep(jiffies_to_msecs(data->heating_complete - curr_jiffies));
|
||||
}
|
||||
|
||||
if (data->data_pending &&
|
||||
time_before64(get_jiffies_64(), data->heating_complete + data->update_interval)) {
|
||||
|
|
@ -115,15 +127,14 @@ static int sht4x_read_values(struct sht4x_data *data)
|
|||
usleep_range(SHT4X_MEAS_DELAY_HPM, SHT4X_MEAS_DELAY_HPM + SHT4X_DELAY_EXTRA);
|
||||
}
|
||||
|
||||
ret = i2c_master_recv(client, raw_data, SHT4X_RESPONSE_LENGTH);
|
||||
if (ret != SHT4X_RESPONSE_LENGTH) {
|
||||
ret = i2c_master_recv(client, raw_data, response_length);
|
||||
if (ret != response_length) {
|
||||
if (ret >= 0)
|
||||
ret = -ENODATA;
|
||||
return ret;
|
||||
}
|
||||
|
||||
t_ticks = raw_data[0] << 8 | raw_data[1];
|
||||
rh_ticks = raw_data[3] << 8 | raw_data[4];
|
||||
|
||||
crc = crc8(sht4x_crc8_table, &raw_data[0], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
|
||||
if (crc != raw_data[2]) {
|
||||
|
|
@ -131,14 +142,19 @@ static int sht4x_read_values(struct sht4x_data *data)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
crc = crc8(sht4x_crc8_table, &raw_data[3], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
|
||||
if (crc != raw_data[5]) {
|
||||
dev_err(&client->dev, "data integrity check failed\n");
|
||||
return -EIO;
|
||||
data->temperature = ((21875 * (int32_t)t_ticks) >> 13) - 45000;
|
||||
|
||||
if (data->chip_id != sts4x) {
|
||||
rh_ticks = raw_data[3] << 8 | raw_data[4];
|
||||
crc = crc8(sht4x_crc8_table, &raw_data[3], SHT4X_WORD_LEN, CRC8_INIT_VALUE);
|
||||
if (crc != raw_data[5]) {
|
||||
dev_err(&client->dev, "data integrity check failed\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
data->humidity = ((15625 * (int32_t)rh_ticks) >> 13) - 6000;
|
||||
}
|
||||
|
||||
data->temperature = ((21875 * (int32_t)t_ticks) >> 13) - 45000;
|
||||
data->humidity = ((15625 * (int32_t)rh_ticks) >> 13) - 6000;
|
||||
data->last_updated = jiffies;
|
||||
data->valid = true;
|
||||
return 0;
|
||||
|
|
@ -190,9 +206,14 @@ static umode_t sht4x_hwmon_visible(const void *data,
|
|||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
const struct sht4x_data *chip_data = data;
|
||||
|
||||
switch (type) {
|
||||
case hwmon_temp:
|
||||
return 0444;
|
||||
case hwmon_humidity:
|
||||
if (chip_data->chip_id == sts4x)
|
||||
return 0;
|
||||
return 0444;
|
||||
case hwmon_chip:
|
||||
return 0644;
|
||||
|
|
@ -392,6 +413,7 @@ static const struct hwmon_chip_info sht4x_chip_info = {
|
|||
|
||||
static int sht4x_probe(struct i2c_client *client)
|
||||
{
|
||||
const struct attribute_group **groups = NULL;
|
||||
struct device *device = &client->dev;
|
||||
struct device *hwmon_dev;
|
||||
struct sht4x_data *data;
|
||||
|
|
@ -410,11 +432,15 @@ static int sht4x_probe(struct i2c_client *client)
|
|||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
data->chip_id = (uintptr_t)i2c_get_match_data(client);
|
||||
data->update_interval = SHT4X_MIN_POLL_INTERVAL;
|
||||
data->client = client;
|
||||
data->heater_power = 200;
|
||||
data->heater_time = 1000;
|
||||
data->heating_complete = get_jiffies_64();
|
||||
if (data->chip_id != sts4x) {
|
||||
data->heater_power = 200;
|
||||
data->heater_time = 1000;
|
||||
data->heating_complete = get_jiffies_64();
|
||||
groups = sht4x_groups;
|
||||
}
|
||||
|
||||
crc8_populate_msb(sht4x_crc8_table, SHT4X_CRC8_POLYNOMIAL);
|
||||
|
||||
|
|
@ -428,19 +454,21 @@ static int sht4x_probe(struct i2c_client *client)
|
|||
client->name,
|
||||
data,
|
||||
&sht4x_chip_info,
|
||||
sht4x_groups);
|
||||
groups);
|
||||
|
||||
return PTR_ERR_OR_ZERO(hwmon_dev);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id sht4x_id[] = {
|
||||
{ .name = "sht4x" },
|
||||
{ .name = "sht4x", .driver_data = sht4x },
|
||||
{ .name = "sts4x", .driver_data = sts4x },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sht4x_id);
|
||||
|
||||
static const struct of_device_id sht4x_of_match[] = {
|
||||
{ .compatible = "sensirion,sht4x" },
|
||||
{ .compatible = "sensirion,sht4x", .data = (void *)sht4x },
|
||||
{ .compatible = "sensirion,sts40", .data = (void *)sts4x },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sht4x_of_match);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user