1 // SPDX-License-Identifier: GPL-2.0-only
4 * Copyright (c) Linumiz 2021
6 * sht4x.c - Linux hwmon driver for SHT4x Temperature and Humidity sensor
8 * Author: Navin Sankar Velliangiri <navin@linumiz.com>
11 #include <linux/crc8.h>
12 #include <linux/delay.h>
13 #include <linux/hwmon.h>
14 #include <linux/hwmon-sysfs.h>
15 #include <linux/i2c.h>
16 #include <linux/jiffies.h>
17 #include <linux/module.h>
20 * Poll intervals (in milliseconds)
22 #define SHT4X_MIN_POLL_INTERVAL 2000
25 * I2C command delays (in microseconds)
27 #define SHT4X_MEAS_DELAY_HPM 8200 /* see t_MEAS,h in datasheet */
28 #define SHT4X_DELAY_EXTRA 10000
33 #define SHT4X_CMD_MEASURE_HPM 0b11111101
34 #define SHT4X_CMD_RESET 0b10010100
35 #define SHT4X_CMD_HEATER_20_1 0b00011110
36 #define SHT4X_CMD_HEATER_20_01 0b00010101
37 #define SHT4X_CMD_HEATER_110_1 0b00101111
38 #define SHT4X_CMD_HEATER_110_01 0b00100100
39 #define SHT4X_CMD_HEATER_200_1 0b00111001
40 #define SHT4X_CMD_HEATER_200_01 0b00110010
42 #define SHT4X_CMD_LEN 1
43 #define SHT4X_CRC8_LEN 1
44 #define SHT4X_WORD_LEN 2
45 #define SHT4X_RESPONSE_LENGTH 6
46 #define SHT4X_CRC8_POLYNOMIAL 0x31
47 #define SHT4X_CRC8_INIT 0xff
48 #define SHT4X_MIN_TEMPERATURE -45000
49 #define SHT4X_MAX_TEMPERATURE 125000
50 #define SHT4X_MIN_HUMIDITY 0
51 #define SHT4X_MAX_HUMIDITY 100000
53 DECLARE_CRC8_TABLE(sht4x_crc8_table
);
56 * struct sht4x_data - All the data required to operate an SHT4X chip
57 * @client: the i2c client associated with the SHT4X
58 * @lock: a mutex that is used to prevent parallel access to the i2c client
59 * @heating_complete: the time that the last heating finished
60 * @data_pending: true if and only if there are measurements to retrieve after heating
61 * @heater_power: the power at which the heater will be started
62 * @heater_time: the time for which the heater will remain turned on
63 * @valid: validity of fields below
64 * @update_interval: the minimum poll interval
65 * @last_updated: the previous time that the SHT4X was polled
66 * @temperature: the latest temperature value received from the SHT4X
67 * @humidity: the latest humidity value received from the SHT4X
70 struct i2c_client
*client
;
71 struct mutex lock
; /* atomic read data updates */
72 unsigned long heating_complete
; /* in jiffies */
74 u32 heater_power
; /* in milli-watts */
75 u32 heater_time
; /* in milli-seconds */
76 bool valid
; /* validity of fields below */
77 long update_interval
; /* in milli-seconds */
78 long last_updated
; /* in jiffies */
84 * sht4x_read_values() - read and parse the raw data from the SHT4X
85 * @data: the struct sht4x_data to use for the lock
86 * Return: 0 if successful, -ERRNO if not
88 static int sht4x_read_values(struct sht4x_data
*data
)
91 u16 t_ticks
, rh_ticks
;
92 unsigned long next_update
;
93 struct i2c_client
*client
= data
->client
;
95 u8 cmd
[SHT4X_CMD_LEN
] = {SHT4X_CMD_MEASURE_HPM
};
96 u8 raw_data
[SHT4X_RESPONSE_LENGTH
];
97 unsigned long curr_jiffies
;
99 mutex_lock(&data
->lock
);
101 curr_jiffies
= jiffies
;
102 if (time_before(curr_jiffies
, data
->heating_complete
))
103 msleep(jiffies_to_msecs(data
->heating_complete
- curr_jiffies
));
105 if (data
->data_pending
&&
106 time_before(jiffies
, data
->heating_complete
+ data
->update_interval
)) {
107 data
->data_pending
= false;
109 next_update
= data
->last_updated
+
110 msecs_to_jiffies(data
->update_interval
);
112 if (data
->valid
&& time_before_eq(jiffies
, next_update
))
115 ret
= i2c_master_send(client
, cmd
, SHT4X_CMD_LEN
);
119 usleep_range(SHT4X_MEAS_DELAY_HPM
, SHT4X_MEAS_DELAY_HPM
+ SHT4X_DELAY_EXTRA
);
122 ret
= i2c_master_recv(client
, raw_data
, SHT4X_RESPONSE_LENGTH
);
123 if (ret
!= SHT4X_RESPONSE_LENGTH
) {
129 t_ticks
= raw_data
[0] << 8 | raw_data
[1];
130 rh_ticks
= raw_data
[3] << 8 | raw_data
[4];
132 crc
= crc8(sht4x_crc8_table
, &raw_data
[0], SHT4X_WORD_LEN
, CRC8_INIT_VALUE
);
133 if (crc
!= raw_data
[2]) {
134 dev_err(&client
->dev
, "data integrity check failed\n");
139 crc
= crc8(sht4x_crc8_table
, &raw_data
[3], SHT4X_WORD_LEN
, CRC8_INIT_VALUE
);
140 if (crc
!= raw_data
[5]) {
141 dev_err(&client
->dev
, "data integrity check failed\n");
146 data
->temperature
= ((21875 * (int32_t)t_ticks
) >> 13) - 45000;
147 data
->humidity
= ((15625 * (int32_t)rh_ticks
) >> 13) - 6000;
148 data
->last_updated
= jiffies
;
153 mutex_unlock(&data
->lock
);
157 static ssize_t
sht4x_interval_write(struct sht4x_data
*data
, long val
)
159 data
->update_interval
= clamp_val(val
, SHT4X_MIN_POLL_INTERVAL
, INT_MAX
);
164 /* sht4x_interval_read() - read the minimum poll interval in milliseconds */
165 static size_t sht4x_interval_read(struct sht4x_data
*data
, long *val
)
167 *val
= data
->update_interval
;
171 /* sht4x_temperature1_read() - read the temperature in millidegrees */
172 static int sht4x_temperature1_read(struct sht4x_data
*data
, long *val
)
176 ret
= sht4x_read_values(data
);
180 *val
= data
->temperature
;
185 /* sht4x_humidity1_read() - read a relative humidity in millipercent */
186 static int sht4x_humidity1_read(struct sht4x_data
*data
, long *val
)
190 ret
= sht4x_read_values(data
);
194 *val
= data
->humidity
;
199 static umode_t
sht4x_hwmon_visible(const void *data
,
200 enum hwmon_sensor_types type
,
201 u32 attr
, int channel
)
214 static int sht4x_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
,
215 u32 attr
, int channel
, long *val
)
217 struct sht4x_data
*data
= dev_get_drvdata(dev
);
221 return sht4x_temperature1_read(data
, val
);
223 return sht4x_humidity1_read(data
, val
);
225 return sht4x_interval_read(data
, val
);
231 static int sht4x_hwmon_write(struct device
*dev
, enum hwmon_sensor_types type
,
232 u32 attr
, int channel
, long val
)
234 struct sht4x_data
*data
= dev_get_drvdata(dev
);
238 return sht4x_interval_write(data
, val
);
244 static ssize_t
heater_enable_show(struct device
*dev
,
245 struct device_attribute
*attr
,
248 struct sht4x_data
*data
= dev_get_drvdata(dev
);
250 return sysfs_emit(buf
, "%u\n", time_before(jiffies
, data
->heating_complete
));
253 static ssize_t
heater_enable_store(struct device
*dev
,
254 struct device_attribute
*attr
,
258 struct sht4x_data
*data
= dev_get_drvdata(dev
);
262 u32 heating_time_bound
;
264 ret
= kstrtobool(buf
, &status
);
270 if (data
->heater_time
== 100) {
271 if (data
->heater_power
== 20)
272 cmd
= SHT4X_CMD_HEATER_20_01
;
273 else if (data
->heater_power
== 110)
274 cmd
= SHT4X_CMD_HEATER_110_01
;
275 else /* data->heater_power == 200 */
276 cmd
= SHT4X_CMD_HEATER_200_01
;
278 heating_time_bound
= 110;
279 } else { /* data->heater_time == 1000 */
280 if (data
->heater_power
== 20)
281 cmd
= SHT4X_CMD_HEATER_20_1
;
282 else if (data
->heater_power
== 110)
283 cmd
= SHT4X_CMD_HEATER_110_1
;
284 else /* data->heater_power == 200 */
285 cmd
= SHT4X_CMD_HEATER_200_1
;
287 heating_time_bound
= 1100;
290 mutex_lock(&data
->lock
);
292 if (time_before(jiffies
, data
->heating_complete
)) {
297 ret
= i2c_master_send(data
->client
, &cmd
, SHT4X_CMD_LEN
);
301 data
->heating_complete
= jiffies
+ msecs_to_jiffies(heating_time_bound
);
302 data
->data_pending
= true;
304 mutex_unlock(&data
->lock
);
308 static ssize_t
heater_power_show(struct device
*dev
,
309 struct device_attribute
*attr
,
312 struct sht4x_data
*data
= dev_get_drvdata(dev
);
314 return sysfs_emit(buf
, "%u\n", data
->heater_power
);
317 static ssize_t
heater_power_store(struct device
*dev
,
318 struct device_attribute
*attr
,
322 struct sht4x_data
*data
= dev_get_drvdata(dev
);
326 ret
= kstrtou32(buf
, 10, &power
);
330 if (power
!= 20 && power
!= 110 && power
!= 200)
333 data
->heater_power
= power
;
338 static ssize_t
heater_time_show(struct device
*dev
,
339 struct device_attribute
*attr
,
342 struct sht4x_data
*data
= dev_get_drvdata(dev
);
344 return sysfs_emit(buf
, "%u\n", data
->heater_time
);
347 static ssize_t
heater_time_store(struct device
*dev
,
348 struct device_attribute
*attr
,
352 struct sht4x_data
*data
= dev_get_drvdata(dev
);
356 ret
= kstrtou32(buf
, 10, &time
);
360 if (time
!= 100 && time
!= 1000)
363 data
->heater_time
= time
;
368 static DEVICE_ATTR_RW(heater_enable
);
369 static DEVICE_ATTR_RW(heater_power
);
370 static DEVICE_ATTR_RW(heater_time
);
372 static struct attribute
*sht4x_attrs
[] = {
373 &dev_attr_heater_enable
.attr
,
374 &dev_attr_heater_power
.attr
,
375 &dev_attr_heater_time
.attr
,
379 ATTRIBUTE_GROUPS(sht4x
);
381 static const struct hwmon_channel_info
* const sht4x_info
[] = {
382 HWMON_CHANNEL_INFO(chip
, HWMON_C_UPDATE_INTERVAL
),
383 HWMON_CHANNEL_INFO(temp
, HWMON_T_INPUT
),
384 HWMON_CHANNEL_INFO(humidity
, HWMON_H_INPUT
),
388 static const struct hwmon_ops sht4x_hwmon_ops
= {
389 .is_visible
= sht4x_hwmon_visible
,
390 .read
= sht4x_hwmon_read
,
391 .write
= sht4x_hwmon_write
,
394 static const struct hwmon_chip_info sht4x_chip_info
= {
395 .ops
= &sht4x_hwmon_ops
,
399 static int sht4x_probe(struct i2c_client
*client
)
401 struct device
*device
= &client
->dev
;
402 struct device
*hwmon_dev
;
403 struct sht4x_data
*data
;
404 u8 cmd
[] = {SHT4X_CMD_RESET
};
408 * we require full i2c support since the sht4x uses multi-byte read and
409 * writes as well as multi-byte commands which are not supported by
412 if (!i2c_check_functionality(client
->adapter
, I2C_FUNC_I2C
))
415 data
= devm_kzalloc(device
, sizeof(*data
), GFP_KERNEL
);
419 data
->update_interval
= SHT4X_MIN_POLL_INTERVAL
;
420 data
->client
= client
;
421 data
->heater_power
= 200;
422 data
->heater_time
= 1000;
423 data
->heating_complete
= jiffies
;
425 mutex_init(&data
->lock
);
427 crc8_populate_msb(sht4x_crc8_table
, SHT4X_CRC8_POLYNOMIAL
);
429 ret
= i2c_master_send(client
, cmd
, SHT4X_CMD_LEN
);
432 if (ret
!= SHT4X_CMD_LEN
)
435 hwmon_dev
= devm_hwmon_device_register_with_info(device
,
441 return PTR_ERR_OR_ZERO(hwmon_dev
);
444 static const struct i2c_device_id sht4x_id
[] = {
448 MODULE_DEVICE_TABLE(i2c
, sht4x_id
);
450 static const struct of_device_id sht4x_of_match
[] = {
451 { .compatible
= "sensirion,sht4x" },
454 MODULE_DEVICE_TABLE(of
, sht4x_of_match
);
456 static struct i2c_driver sht4x_driver
= {
459 .of_match_table
= sht4x_of_match
,
461 .probe
= sht4x_probe
,
462 .id_table
= sht4x_id
,
465 module_i2c_driver(sht4x_driver
);
467 MODULE_AUTHOR("Navin Sankar Velliangiri <navin@linumiz.com>");
468 MODULE_DESCRIPTION("Sensirion SHT4x humidity and temperature sensor driver");
469 MODULE_LICENSE("GPL v2");