1 | // SPDX-License-Identifier: GPL-2.0-or-later |
---|---|
2 | /* Sensirion SHT3x-DIS humidity and temperature sensor driver. |
3 | * The SHT3x comes in many different versions, this driver is for the |
4 | * I2C version only. |
5 | * |
6 | * Copyright (C) 2016 Sensirion AG, Switzerland |
7 | * Author: David Frey <david.frey@sensirion.com> |
8 | * Author: Pascal Sachs <pascal.sachs@sensirion.com> |
9 | */ |
10 | |
11 | #include <asm/page.h> |
12 | #include <linux/crc8.h> |
13 | #include <linux/debugfs.h> |
14 | #include <linux/delay.h> |
15 | #include <linux/err.h> |
16 | #include <linux/hwmon.h> |
17 | #include <linux/hwmon-sysfs.h> |
18 | #include <linux/i2c.h> |
19 | #include <linux/init.h> |
20 | #include <linux/kernel.h> |
21 | #include <linux/module.h> |
22 | #include <linux/slab.h> |
23 | #include <linux/jiffies.h> |
24 | |
25 | /* commands (high repeatability mode) */ |
26 | static const unsigned char sht3x_cmd_measure_single_hpm[] = { 0x24, 0x00 }; |
27 | |
28 | /* commands (medium repeatability mode) */ |
29 | static const unsigned char sht3x_cmd_measure_single_mpm[] = { 0x24, 0x0b }; |
30 | |
31 | /* commands (low repeatability mode) */ |
32 | static const unsigned char sht3x_cmd_measure_single_lpm[] = { 0x24, 0x16 }; |
33 | |
34 | /* commands for periodic mode */ |
35 | static const unsigned char sht3x_cmd_measure_periodic_mode[] = { 0xe0, 0x00 }; |
36 | static const unsigned char sht3x_cmd_break[] = { 0x30, 0x93 }; |
37 | |
38 | /* commands for heater control */ |
39 | static const unsigned char sht3x_cmd_heater_on[] = { 0x30, 0x6d }; |
40 | static const unsigned char sht3x_cmd_heater_off[] = { 0x30, 0x66 }; |
41 | |
42 | /* other commands */ |
43 | static const unsigned char sht3x_cmd_read_status_reg[] = { 0xf3, 0x2d }; |
44 | static const unsigned char sht3x_cmd_clear_status_reg[] = { 0x30, 0x41 }; |
45 | static const unsigned char sht3x_cmd_read_serial_number[] = { 0x37, 0x80 }; |
46 | |
47 | /* delays for single-shot mode i2c commands, both in us */ |
48 | #define SHT3X_SINGLE_WAIT_TIME_HPM 15000 |
49 | #define SHT3X_SINGLE_WAIT_TIME_MPM 6000 |
50 | #define SHT3X_SINGLE_WAIT_TIME_LPM 4000 |
51 | |
52 | #define SHT3X_WORD_LEN 2 |
53 | #define SHT3X_CMD_LENGTH 2 |
54 | #define SHT3X_CRC8_LEN 1 |
55 | #define SHT3X_RESPONSE_LENGTH 6 |
56 | #define SHT3X_CRC8_POLYNOMIAL 0x31 |
57 | #define SHT3X_CRC8_INIT 0xFF |
58 | #define SHT3X_MIN_TEMPERATURE -45000 |
59 | #define SHT3X_MAX_TEMPERATURE 130000 |
60 | #define SHT3X_MIN_HUMIDITY 0 |
61 | #define SHT3X_MAX_HUMIDITY 100000 |
62 | |
63 | enum sht3x_chips { |
64 | sht3x, |
65 | sts3x, |
66 | }; |
67 | |
68 | enum sht3x_limits { |
69 | limit_max = 0, |
70 | limit_max_hyst, |
71 | limit_min, |
72 | limit_min_hyst, |
73 | }; |
74 | |
75 | enum sht3x_repeatability { |
76 | low_repeatability, |
77 | medium_repeatability, |
78 | high_repeatability, |
79 | }; |
80 | |
81 | DECLARE_CRC8_TABLE(sht3x_crc8_table); |
82 | |
83 | /* periodic measure commands (high repeatability mode) */ |
84 | static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = { |
85 | /* 0.5 measurements per second */ |
86 | {0x20, 0x32}, |
87 | /* 1 measurements per second */ |
88 | {0x21, 0x30}, |
89 | /* 2 measurements per second */ |
90 | {0x22, 0x36}, |
91 | /* 4 measurements per second */ |
92 | {0x23, 0x34}, |
93 | /* 10 measurements per second */ |
94 | {0x27, 0x37}, |
95 | }; |
96 | |
97 | /* periodic measure commands (medium repeatability) */ |
98 | static const char periodic_measure_commands_mpm[][SHT3X_CMD_LENGTH] = { |
99 | /* 0.5 measurements per second */ |
100 | {0x20, 0x24}, |
101 | /* 1 measurements per second */ |
102 | {0x21, 0x26}, |
103 | /* 2 measurements per second */ |
104 | {0x22, 0x20}, |
105 | /* 4 measurements per second */ |
106 | {0x23, 0x22}, |
107 | /* 10 measurements per second */ |
108 | {0x27, 0x21}, |
109 | }; |
110 | |
111 | /* periodic measure commands (low repeatability mode) */ |
112 | static const char periodic_measure_commands_lpm[][SHT3X_CMD_LENGTH] = { |
113 | /* 0.5 measurements per second */ |
114 | {0x20, 0x2f}, |
115 | /* 1 measurements per second */ |
116 | {0x21, 0x2d}, |
117 | /* 2 measurements per second */ |
118 | {0x22, 0x2b}, |
119 | /* 4 measurements per second */ |
120 | {0x23, 0x29}, |
121 | /* 10 measurements per second */ |
122 | {0x27, 0x2a}, |
123 | }; |
124 | |
125 | struct sht3x_limit_commands { |
126 | const char read_command[SHT3X_CMD_LENGTH]; |
127 | const char write_command[SHT3X_CMD_LENGTH]; |
128 | }; |
129 | |
130 | static const struct sht3x_limit_commands limit_commands[] = { |
131 | /* temp1_max, humidity1_max */ |
132 | [limit_max] = { {0xe1, 0x1f}, {0x61, 0x1d} }, |
133 | /* temp_1_max_hyst, humidity1_max_hyst */ |
134 | [limit_max_hyst] = { {0xe1, 0x14}, {0x61, 0x16} }, |
135 | /* temp1_min, humidity1_min */ |
136 | [limit_min] = { {0xe1, 0x02}, {0x61, 0x00} }, |
137 | /* temp_1_min_hyst, humidity1_min_hyst */ |
138 | [limit_min_hyst] = { {0xe1, 0x09}, {0x61, 0x0B} }, |
139 | }; |
140 | |
141 | #define SHT3X_NUM_LIMIT_CMD ARRAY_SIZE(limit_commands) |
142 | |
143 | static const u16 mode_to_update_interval[] = { |
144 | 0, |
145 | 2000, |
146 | 1000, |
147 | 500, |
148 | 250, |
149 | 100, |
150 | }; |
151 | |
152 | static const struct hwmon_channel_info * const sht3x_channel_info[] = { |
153 | HWMON_CHANNEL_INFO(chip, HWMON_C_UPDATE_INTERVAL), |
154 | HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MIN | |
155 | HWMON_T_MIN_HYST | HWMON_T_MAX | |
156 | HWMON_T_MAX_HYST | HWMON_T_ALARM), |
157 | HWMON_CHANNEL_INFO(humidity, HWMON_H_INPUT | HWMON_H_MIN | |
158 | HWMON_H_MIN_HYST | HWMON_H_MAX | |
159 | HWMON_H_MAX_HYST | HWMON_H_ALARM), |
160 | NULL, |
161 | }; |
162 | |
163 | struct sht3x_data { |
164 | struct i2c_client *client; |
165 | enum sht3x_chips chip_id; |
166 | struct mutex i2c_lock; /* lock for sending i2c commands */ |
167 | struct mutex data_lock; /* lock for updating driver data */ |
168 | |
169 | u8 mode; |
170 | const unsigned char *command; |
171 | u32 wait_time; /* in us*/ |
172 | unsigned long last_update; /* last update in periodic mode*/ |
173 | enum sht3x_repeatability repeatability; |
174 | u32 serial_number; |
175 | |
176 | /* |
177 | * cached values for temperature and humidity and limits |
178 | * the limits arrays have the following order: |
179 | * max, max_hyst, min, min_hyst |
180 | */ |
181 | int temperature; |
182 | int temperature_limits[SHT3X_NUM_LIMIT_CMD]; |
183 | u32 humidity; |
184 | u32 humidity_limits[SHT3X_NUM_LIMIT_CMD]; |
185 | }; |
186 | |
187 | static u8 get_mode_from_update_interval(u16 value) |
188 | { |
189 | size_t index; |
190 | u8 number_of_modes = ARRAY_SIZE(mode_to_update_interval); |
191 | |
192 | if (value == 0) |
193 | return 0; |
194 | |
195 | /* find next faster update interval */ |
196 | for (index = 1; index < number_of_modes; index++) { |
197 | if (mode_to_update_interval[index] <= value) |
198 | return index; |
199 | } |
200 | |
201 | return number_of_modes - 1; |
202 | } |
203 | |
204 | static int sht3x_read_from_command(struct i2c_client *client, |
205 | struct sht3x_data *data, |
206 | const char *command, |
207 | char *buf, int length, u32 wait_time) |
208 | { |
209 | int ret; |
210 | |
211 | mutex_lock(&data->i2c_lock); |
212 | ret = i2c_master_send(client, buf: command, SHT3X_CMD_LENGTH); |
213 | |
214 | if (ret != SHT3X_CMD_LENGTH) { |
215 | ret = ret < 0 ? ret : -EIO; |
216 | goto out; |
217 | } |
218 | |
219 | if (wait_time) |
220 | usleep_range(min: wait_time, max: wait_time + 1000); |
221 | |
222 | ret = i2c_master_recv(client, buf, count: length); |
223 | if (ret != length) { |
224 | ret = ret < 0 ? ret : -EIO; |
225 | goto out; |
226 | } |
227 | |
228 | ret = 0; |
229 | out: |
230 | mutex_unlock(lock: &data->i2c_lock); |
231 | return ret; |
232 | } |
233 | |
234 | static int sht3x_extract_temperature(u16 raw) |
235 | { |
236 | /* |
237 | * From datasheet: |
238 | * T = -45 + 175 * ST / 2^16 |
239 | * Adapted for integer fixed point (3 digit) arithmetic. |
240 | */ |
241 | return ((21875 * (int)raw) >> 13) - 45000; |
242 | } |
243 | |
244 | static u32 sht3x_extract_humidity(u16 raw) |
245 | { |
246 | /* |
247 | * From datasheet: |
248 | * RH = 100 * SRH / 2^16 |
249 | * Adapted for integer fixed point (3 digit) arithmetic. |
250 | */ |
251 | return (12500 * (u32)raw) >> 13; |
252 | } |
253 | |
254 | static struct sht3x_data *sht3x_update_client(struct device *dev) |
255 | { |
256 | struct sht3x_data *data = dev_get_drvdata(dev); |
257 | struct i2c_client *client = data->client; |
258 | u16 interval_ms = mode_to_update_interval[data->mode]; |
259 | unsigned long interval_jiffies = msecs_to_jiffies(m: interval_ms); |
260 | unsigned char buf[SHT3X_RESPONSE_LENGTH]; |
261 | u16 val; |
262 | int ret = 0; |
263 | |
264 | mutex_lock(&data->data_lock); |
265 | /* |
266 | * Only update cached readings once per update interval in periodic |
267 | * mode. In single shot mode the sensor measures values on demand, so |
268 | * every time the sysfs interface is called, a measurement is triggered. |
269 | * In periodic mode however, the measurement process is handled |
270 | * internally by the sensor and reading out sensor values only makes |
271 | * sense if a new reading is available. |
272 | */ |
273 | if (time_after(jiffies, data->last_update + interval_jiffies)) { |
274 | ret = sht3x_read_from_command(client, data, command: data->command, buf, |
275 | length: sizeof(buf), wait_time: data->wait_time); |
276 | if (ret) |
277 | goto out; |
278 | |
279 | val = be16_to_cpup(p: (__be16 *)buf); |
280 | data->temperature = sht3x_extract_temperature(raw: val); |
281 | val = be16_to_cpup(p: (__be16 *)(buf + 3)); |
282 | data->humidity = sht3x_extract_humidity(raw: val); |
283 | data->last_update = jiffies; |
284 | } |
285 | |
286 | out: |
287 | mutex_unlock(lock: &data->data_lock); |
288 | if (ret) |
289 | return ERR_PTR(error: ret); |
290 | |
291 | return data; |
292 | } |
293 | |
294 | static int temp1_input_read(struct device *dev) |
295 | { |
296 | struct sht3x_data *data = sht3x_update_client(dev); |
297 | |
298 | if (IS_ERR(ptr: data)) |
299 | return PTR_ERR(ptr: data); |
300 | |
301 | return data->temperature; |
302 | } |
303 | |
304 | static int humidity1_input_read(struct device *dev) |
305 | { |
306 | struct sht3x_data *data = sht3x_update_client(dev); |
307 | |
308 | if (IS_ERR(ptr: data)) |
309 | return PTR_ERR(ptr: data); |
310 | |
311 | return data->humidity; |
312 | } |
313 | |
314 | /* |
315 | * limits_update must only be called from probe or with data_lock held |
316 | */ |
317 | static int limits_update(struct sht3x_data *data) |
318 | { |
319 | int ret; |
320 | u8 index; |
321 | int temperature; |
322 | u32 humidity; |
323 | u16 raw; |
324 | char buffer[SHT3X_RESPONSE_LENGTH]; |
325 | const struct sht3x_limit_commands *commands; |
326 | struct i2c_client *client = data->client; |
327 | |
328 | for (index = 0; index < SHT3X_NUM_LIMIT_CMD; index++) { |
329 | commands = &limit_commands[index]; |
330 | ret = sht3x_read_from_command(client, data, |
331 | command: commands->read_command, buf: buffer, |
332 | SHT3X_RESPONSE_LENGTH, wait_time: 0); |
333 | |
334 | if (ret) |
335 | return ret; |
336 | |
337 | raw = be16_to_cpup(p: (__be16 *)buffer); |
338 | temperature = sht3x_extract_temperature(raw: (raw & 0x01ff) << 7); |
339 | humidity = sht3x_extract_humidity(raw: raw & 0xfe00); |
340 | data->temperature_limits[index] = temperature; |
341 | data->humidity_limits[index] = humidity; |
342 | } |
343 | |
344 | return ret; |
345 | } |
346 | |
347 | static int temp1_limit_read(struct device *dev, int index) |
348 | { |
349 | struct sht3x_data *data = dev_get_drvdata(dev); |
350 | |
351 | return data->temperature_limits[index]; |
352 | } |
353 | |
354 | static int humidity1_limit_read(struct device *dev, int index) |
355 | { |
356 | struct sht3x_data *data = dev_get_drvdata(dev); |
357 | |
358 | return data->humidity_limits[index]; |
359 | } |
360 | |
361 | /* |
362 | * limit_write must only be called with data_lock held |
363 | */ |
364 | static size_t limit_write(struct device *dev, |
365 | u8 index, |
366 | int temperature, |
367 | u32 humidity) |
368 | { |
369 | char buffer[SHT3X_CMD_LENGTH + SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; |
370 | char *position = buffer; |
371 | int ret; |
372 | u16 raw; |
373 | struct sht3x_data *data = dev_get_drvdata(dev); |
374 | struct i2c_client *client = data->client; |
375 | const struct sht3x_limit_commands *commands; |
376 | |
377 | commands = &limit_commands[index]; |
378 | |
379 | memcpy(position, commands->write_command, SHT3X_CMD_LENGTH); |
380 | position += SHT3X_CMD_LENGTH; |
381 | /* |
382 | * ST = (T + 45) / 175 * 2^16 |
383 | * SRH = RH / 100 * 2^16 |
384 | * adapted for fixed point arithmetic and packed the same as |
385 | * in limit_read() |
386 | */ |
387 | raw = ((u32)(temperature + 45000) * 24543) >> (16 + 7); |
388 | raw |= ((humidity * 42950) >> 16) & 0xfe00; |
389 | |
390 | *((__be16 *)position) = cpu_to_be16(raw); |
391 | position += SHT3X_WORD_LEN; |
392 | *position = crc8(table: sht3x_crc8_table, |
393 | pdata: position - SHT3X_WORD_LEN, |
394 | SHT3X_WORD_LEN, |
395 | SHT3X_CRC8_INIT); |
396 | |
397 | mutex_lock(&data->i2c_lock); |
398 | ret = i2c_master_send(client, buf: buffer, count: sizeof(buffer)); |
399 | mutex_unlock(lock: &data->i2c_lock); |
400 | |
401 | if (ret != sizeof(buffer)) |
402 | return ret < 0 ? ret : -EIO; |
403 | |
404 | data->temperature_limits[index] = temperature; |
405 | data->humidity_limits[index] = humidity; |
406 | |
407 | return 0; |
408 | } |
409 | |
410 | static int temp1_limit_write(struct device *dev, int index, int val) |
411 | { |
412 | int temperature; |
413 | int ret; |
414 | struct sht3x_data *data = dev_get_drvdata(dev); |
415 | |
416 | temperature = clamp_val(val, SHT3X_MIN_TEMPERATURE, |
417 | SHT3X_MAX_TEMPERATURE); |
418 | mutex_lock(&data->data_lock); |
419 | ret = limit_write(dev, index, temperature, |
420 | humidity: data->humidity_limits[index]); |
421 | mutex_unlock(lock: &data->data_lock); |
422 | |
423 | return ret; |
424 | } |
425 | |
426 | static int humidity1_limit_write(struct device *dev, int index, int val) |
427 | { |
428 | u32 humidity; |
429 | int ret; |
430 | struct sht3x_data *data = dev_get_drvdata(dev); |
431 | |
432 | humidity = clamp_val(val, SHT3X_MIN_HUMIDITY, SHT3X_MAX_HUMIDITY); |
433 | mutex_lock(&data->data_lock); |
434 | ret = limit_write(dev, index, temperature: data->temperature_limits[index], |
435 | humidity); |
436 | mutex_unlock(lock: &data->data_lock); |
437 | |
438 | return ret; |
439 | } |
440 | |
441 | static void sht3x_select_command(struct sht3x_data *data) |
442 | { |
443 | /* |
444 | * For single-shot mode, only non blocking mode is support, |
445 | * we have to wait ourselves for result. |
446 | */ |
447 | if (data->mode > 0) { |
448 | data->command = sht3x_cmd_measure_periodic_mode; |
449 | data->wait_time = 0; |
450 | } else { |
451 | if (data->repeatability == high_repeatability) { |
452 | data->command = sht3x_cmd_measure_single_hpm; |
453 | data->wait_time = SHT3X_SINGLE_WAIT_TIME_HPM; |
454 | } else if (data->repeatability == medium_repeatability) { |
455 | data->command = sht3x_cmd_measure_single_mpm; |
456 | data->wait_time = SHT3X_SINGLE_WAIT_TIME_MPM; |
457 | } else { |
458 | data->command = sht3x_cmd_measure_single_lpm; |
459 | data->wait_time = SHT3X_SINGLE_WAIT_TIME_LPM; |
460 | } |
461 | } |
462 | } |
463 | |
464 | static int status_register_read(struct device *dev, |
465 | char *buffer, int length) |
466 | { |
467 | int ret; |
468 | struct sht3x_data *data = dev_get_drvdata(dev); |
469 | struct i2c_client *client = data->client; |
470 | |
471 | ret = sht3x_read_from_command(client, data, command: sht3x_cmd_read_status_reg, |
472 | buf: buffer, length, wait_time: 0); |
473 | |
474 | return ret; |
475 | } |
476 | |
477 | static int temp1_alarm_read(struct device *dev) |
478 | { |
479 | char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; |
480 | int ret; |
481 | |
482 | ret = status_register_read(dev, buffer, |
483 | SHT3X_WORD_LEN + SHT3X_CRC8_LEN); |
484 | if (ret) |
485 | return ret; |
486 | |
487 | return !!(buffer[0] & 0x04); |
488 | } |
489 | |
490 | static int humidity1_alarm_read(struct device *dev) |
491 | { |
492 | char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; |
493 | int ret; |
494 | |
495 | ret = status_register_read(dev, buffer, |
496 | SHT3X_WORD_LEN + SHT3X_CRC8_LEN); |
497 | if (ret) |
498 | return ret; |
499 | |
500 | return !!(buffer[0] & 0x08); |
501 | } |
502 | |
503 | static ssize_t heater_enable_show(struct device *dev, |
504 | struct device_attribute *attr, |
505 | char *buf) |
506 | { |
507 | char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN]; |
508 | int ret; |
509 | |
510 | ret = status_register_read(dev, buffer, |
511 | SHT3X_WORD_LEN + SHT3X_CRC8_LEN); |
512 | if (ret) |
513 | return ret; |
514 | |
515 | return sysfs_emit(buf, fmt: "%d\n", !!(buffer[0] & 0x20)); |
516 | } |
517 | |
518 | static ssize_t heater_enable_store(struct device *dev, |
519 | struct device_attribute *attr, |
520 | const char *buf, |
521 | size_t count) |
522 | { |
523 | struct sht3x_data *data = dev_get_drvdata(dev); |
524 | struct i2c_client *client = data->client; |
525 | int ret; |
526 | bool status; |
527 | |
528 | ret = kstrtobool(s: buf, res: &status); |
529 | if (ret) |
530 | return ret; |
531 | |
532 | mutex_lock(&data->i2c_lock); |
533 | |
534 | if (status) |
535 | ret = i2c_master_send(client, buf: (char *)&sht3x_cmd_heater_on, |
536 | SHT3X_CMD_LENGTH); |
537 | else |
538 | ret = i2c_master_send(client, buf: (char *)&sht3x_cmd_heater_off, |
539 | SHT3X_CMD_LENGTH); |
540 | |
541 | mutex_unlock(lock: &data->i2c_lock); |
542 | |
543 | return ret; |
544 | } |
545 | |
546 | static int update_interval_read(struct device *dev) |
547 | { |
548 | struct sht3x_data *data = dev_get_drvdata(dev); |
549 | |
550 | return mode_to_update_interval[data->mode]; |
551 | } |
552 | |
553 | static int update_interval_write(struct device *dev, int val) |
554 | { |
555 | u8 mode; |
556 | int ret; |
557 | const char *command; |
558 | struct sht3x_data *data = dev_get_drvdata(dev); |
559 | struct i2c_client *client = data->client; |
560 | |
561 | mode = get_mode_from_update_interval(value: val); |
562 | |
563 | mutex_lock(&data->data_lock); |
564 | /* mode did not change */ |
565 | if (mode == data->mode) { |
566 | mutex_unlock(lock: &data->data_lock); |
567 | return 0; |
568 | } |
569 | |
570 | mutex_lock(&data->i2c_lock); |
571 | /* |
572 | * Abort periodic measure mode. |
573 | * To do any changes to the configuration while in periodic mode, we |
574 | * have to send a break command to the sensor, which then falls back |
575 | * to single shot (mode = 0). |
576 | */ |
577 | if (data->mode > 0) { |
578 | ret = i2c_master_send(client, buf: sht3x_cmd_break, |
579 | SHT3X_CMD_LENGTH); |
580 | if (ret != SHT3X_CMD_LENGTH) |
581 | goto out; |
582 | data->mode = 0; |
583 | } |
584 | |
585 | if (mode > 0) { |
586 | if (data->repeatability == high_repeatability) |
587 | command = periodic_measure_commands_hpm[mode - 1]; |
588 | else if (data->repeatability == medium_repeatability) |
589 | command = periodic_measure_commands_mpm[mode - 1]; |
590 | else |
591 | command = periodic_measure_commands_lpm[mode - 1]; |
592 | |
593 | /* select mode */ |
594 | ret = i2c_master_send(client, buf: command, SHT3X_CMD_LENGTH); |
595 | if (ret != SHT3X_CMD_LENGTH) |
596 | goto out; |
597 | } |
598 | |
599 | /* select mode and command */ |
600 | data->mode = mode; |
601 | sht3x_select_command(data); |
602 | |
603 | out: |
604 | mutex_unlock(lock: &data->i2c_lock); |
605 | mutex_unlock(lock: &data->data_lock); |
606 | if (ret != SHT3X_CMD_LENGTH) |
607 | return ret < 0 ? ret : -EIO; |
608 | |
609 | return 0; |
610 | } |
611 | |
612 | static ssize_t repeatability_show(struct device *dev, |
613 | struct device_attribute *attr, |
614 | char *buf) |
615 | { |
616 | struct sht3x_data *data = dev_get_drvdata(dev); |
617 | |
618 | return sysfs_emit(buf, fmt: "%d\n", data->repeatability); |
619 | } |
620 | |
621 | static ssize_t repeatability_store(struct device *dev, |
622 | struct device_attribute *attr, |
623 | const char *buf, |
624 | size_t count) |
625 | { |
626 | int ret; |
627 | u8 val; |
628 | |
629 | struct sht3x_data *data = dev_get_drvdata(dev); |
630 | |
631 | ret = kstrtou8(s: buf, base: 0, res: &val); |
632 | if (ret) |
633 | return ret; |
634 | |
635 | if (val > 2) |
636 | return -EINVAL; |
637 | |
638 | data->repeatability = val; |
639 | |
640 | return count; |
641 | } |
642 | |
643 | static SENSOR_DEVICE_ATTR_RW(heater_enable, heater_enable, 0); |
644 | static SENSOR_DEVICE_ATTR_RW(repeatability, repeatability, 0); |
645 | |
646 | static struct attribute *sht3x_attrs[] = { |
647 | &sensor_dev_attr_heater_enable.dev_attr.attr, |
648 | &sensor_dev_attr_repeatability.dev_attr.attr, |
649 | NULL |
650 | }; |
651 | |
652 | ATTRIBUTE_GROUPS(sht3x); |
653 | |
654 | static umode_t sht3x_is_visible(const void *data, enum hwmon_sensor_types type, |
655 | u32 attr, int channel) |
656 | { |
657 | const struct sht3x_data *chip_data = data; |
658 | |
659 | switch (type) { |
660 | case hwmon_chip: |
661 | switch (attr) { |
662 | case hwmon_chip_update_interval: |
663 | return 0644; |
664 | default: |
665 | break; |
666 | } |
667 | break; |
668 | case hwmon_temp: |
669 | switch (attr) { |
670 | case hwmon_temp_input: |
671 | case hwmon_temp_alarm: |
672 | return 0444; |
673 | case hwmon_temp_max: |
674 | case hwmon_temp_max_hyst: |
675 | case hwmon_temp_min: |
676 | case hwmon_temp_min_hyst: |
677 | return 0644; |
678 | default: |
679 | break; |
680 | } |
681 | break; |
682 | case hwmon_humidity: |
683 | if (chip_data->chip_id == sts3x) |
684 | break; |
685 | switch (attr) { |
686 | case hwmon_humidity_input: |
687 | case hwmon_humidity_alarm: |
688 | return 0444; |
689 | case hwmon_humidity_max: |
690 | case hwmon_humidity_max_hyst: |
691 | case hwmon_humidity_min: |
692 | case hwmon_humidity_min_hyst: |
693 | return 0644; |
694 | default: |
695 | break; |
696 | } |
697 | break; |
698 | default: |
699 | break; |
700 | } |
701 | |
702 | return 0; |
703 | } |
704 | |
705 | static int sht3x_read(struct device *dev, enum hwmon_sensor_types type, |
706 | u32 attr, int channel, long *val) |
707 | { |
708 | enum sht3x_limits index; |
709 | |
710 | switch (type) { |
711 | case hwmon_chip: |
712 | switch (attr) { |
713 | case hwmon_chip_update_interval: |
714 | *val = update_interval_read(dev); |
715 | break; |
716 | default: |
717 | return -EOPNOTSUPP; |
718 | } |
719 | break; |
720 | case hwmon_temp: |
721 | switch (attr) { |
722 | case hwmon_temp_input: |
723 | *val = temp1_input_read(dev); |
724 | break; |
725 | case hwmon_temp_alarm: |
726 | *val = temp1_alarm_read(dev); |
727 | break; |
728 | case hwmon_temp_max: |
729 | index = limit_max; |
730 | *val = temp1_limit_read(dev, index); |
731 | break; |
732 | case hwmon_temp_max_hyst: |
733 | index = limit_max_hyst; |
734 | *val = temp1_limit_read(dev, index); |
735 | break; |
736 | case hwmon_temp_min: |
737 | index = limit_min; |
738 | *val = temp1_limit_read(dev, index); |
739 | break; |
740 | case hwmon_temp_min_hyst: |
741 | index = limit_min_hyst; |
742 | *val = temp1_limit_read(dev, index); |
743 | break; |
744 | default: |
745 | return -EOPNOTSUPP; |
746 | } |
747 | break; |
748 | case hwmon_humidity: |
749 | switch (attr) { |
750 | case hwmon_humidity_input: |
751 | *val = humidity1_input_read(dev); |
752 | break; |
753 | case hwmon_humidity_alarm: |
754 | *val = humidity1_alarm_read(dev); |
755 | break; |
756 | case hwmon_humidity_max: |
757 | index = limit_max; |
758 | *val = humidity1_limit_read(dev, index); |
759 | break; |
760 | case hwmon_humidity_max_hyst: |
761 | index = limit_max_hyst; |
762 | *val = humidity1_limit_read(dev, index); |
763 | break; |
764 | case hwmon_humidity_min: |
765 | index = limit_min; |
766 | *val = humidity1_limit_read(dev, index); |
767 | break; |
768 | case hwmon_humidity_min_hyst: |
769 | index = limit_min_hyst; |
770 | *val = humidity1_limit_read(dev, index); |
771 | break; |
772 | default: |
773 | return -EOPNOTSUPP; |
774 | } |
775 | break; |
776 | default: |
777 | return -EOPNOTSUPP; |
778 | } |
779 | |
780 | return 0; |
781 | } |
782 | |
783 | static int sht3x_write(struct device *dev, enum hwmon_sensor_types type, |
784 | u32 attr, int channel, long val) |
785 | { |
786 | enum sht3x_limits index; |
787 | |
788 | switch (type) { |
789 | case hwmon_chip: |
790 | switch (attr) { |
791 | case hwmon_chip_update_interval: |
792 | return update_interval_write(dev, val); |
793 | default: |
794 | return -EOPNOTSUPP; |
795 | } |
796 | case hwmon_temp: |
797 | switch (attr) { |
798 | case hwmon_temp_max: |
799 | index = limit_max; |
800 | break; |
801 | case hwmon_temp_max_hyst: |
802 | index = limit_max_hyst; |
803 | break; |
804 | case hwmon_temp_min: |
805 | index = limit_min; |
806 | break; |
807 | case hwmon_temp_min_hyst: |
808 | index = limit_min_hyst; |
809 | break; |
810 | default: |
811 | return -EOPNOTSUPP; |
812 | } |
813 | return temp1_limit_write(dev, index, val); |
814 | case hwmon_humidity: |
815 | switch (attr) { |
816 | case hwmon_humidity_max: |
817 | index = limit_max; |
818 | break; |
819 | case hwmon_humidity_max_hyst: |
820 | index = limit_max_hyst; |
821 | break; |
822 | case hwmon_humidity_min: |
823 | index = limit_min; |
824 | break; |
825 | case hwmon_humidity_min_hyst: |
826 | index = limit_min_hyst; |
827 | break; |
828 | default: |
829 | return -EOPNOTSUPP; |
830 | } |
831 | return humidity1_limit_write(dev, index, val); |
832 | default: |
833 | return -EOPNOTSUPP; |
834 | } |
835 | } |
836 | |
837 | static void sht3x_serial_number_read(struct sht3x_data *data) |
838 | { |
839 | int ret; |
840 | char buffer[SHT3X_RESPONSE_LENGTH]; |
841 | struct i2c_client *client = data->client; |
842 | |
843 | ret = sht3x_read_from_command(client, data, |
844 | command: sht3x_cmd_read_serial_number, |
845 | buf: buffer, |
846 | SHT3X_RESPONSE_LENGTH, wait_time: 0); |
847 | if (ret) |
848 | return; |
849 | |
850 | data->serial_number = (buffer[0] << 24) | (buffer[1] << 16) | |
851 | (buffer[3] << 8) | buffer[4]; |
852 | |
853 | debugfs_create_u32(name: "serial_number", mode: 0444, parent: client->debugfs, value: &data->serial_number); |
854 | } |
855 | |
856 | static const struct hwmon_ops sht3x_ops = { |
857 | .is_visible = sht3x_is_visible, |
858 | .read = sht3x_read, |
859 | .write = sht3x_write, |
860 | }; |
861 | |
862 | static const struct hwmon_chip_info sht3x_chip_info = { |
863 | .ops = &sht3x_ops, |
864 | .info = sht3x_channel_info, |
865 | }; |
866 | |
867 | static int sht3x_probe(struct i2c_client *client) |
868 | { |
869 | int ret; |
870 | struct sht3x_data *data; |
871 | struct device *hwmon_dev; |
872 | struct i2c_adapter *adap = client->adapter; |
873 | struct device *dev = &client->dev; |
874 | |
875 | /* |
876 | * we require full i2c support since the sht3x uses multi-byte read and |
877 | * writes as well as multi-byte commands which are not supported by |
878 | * the smbus protocol |
879 | */ |
880 | if (!i2c_check_functionality(adap, I2C_FUNC_I2C)) |
881 | return -ENODEV; |
882 | |
883 | ret = i2c_master_send(client, buf: sht3x_cmd_clear_status_reg, |
884 | SHT3X_CMD_LENGTH); |
885 | if (ret != SHT3X_CMD_LENGTH) |
886 | return ret < 0 ? ret : -ENODEV; |
887 | |
888 | data = devm_kzalloc(dev, size: sizeof(*data), GFP_KERNEL); |
889 | if (!data) |
890 | return -ENOMEM; |
891 | |
892 | data->repeatability = high_repeatability; |
893 | data->mode = 0; |
894 | data->last_update = jiffies - msecs_to_jiffies(m: 3000); |
895 | data->client = client; |
896 | data->chip_id = (uintptr_t)i2c_get_match_data(client); |
897 | crc8_populate_msb(table: sht3x_crc8_table, SHT3X_CRC8_POLYNOMIAL); |
898 | |
899 | sht3x_select_command(data); |
900 | |
901 | mutex_init(&data->i2c_lock); |
902 | mutex_init(&data->data_lock); |
903 | |
904 | /* |
905 | * An attempt to read limits register too early |
906 | * causes a NACK response from the chip. |
907 | * Waiting for an empirical delay of 500 us solves the issue. |
908 | */ |
909 | usleep_range(min: 500, max: 600); |
910 | |
911 | ret = limits_update(data); |
912 | if (ret) |
913 | return ret; |
914 | |
915 | hwmon_dev = devm_hwmon_device_register_with_info(dev, name: client->name, drvdata: data, |
916 | info: &sht3x_chip_info, extra_groups: sht3x_groups); |
917 | if (IS_ERR(ptr: hwmon_dev)) |
918 | return PTR_ERR(ptr: hwmon_dev); |
919 | |
920 | sht3x_serial_number_read(data); |
921 | |
922 | return 0; |
923 | } |
924 | |
925 | /* device ID table */ |
926 | static const struct i2c_device_id sht3x_ids[] = { |
927 | {"sht3x", sht3x}, |
928 | {"sts3x", sts3x}, |
929 | {} |
930 | }; |
931 | |
932 | MODULE_DEVICE_TABLE(i2c, sht3x_ids); |
933 | |
934 | static struct i2c_driver sht3x_i2c_driver = { |
935 | .driver.name = "sht3x", |
936 | .probe = sht3x_probe, |
937 | .id_table = sht3x_ids, |
938 | }; |
939 | module_i2c_driver(sht3x_i2c_driver); |
940 | |
941 | MODULE_AUTHOR("David Frey <david.frey@sensirion.com>"); |
942 | MODULE_AUTHOR("Pascal Sachs <pascal.sachs@sensirion.com>"); |
943 | MODULE_DESCRIPTION("Sensirion SHT3x humidity and temperature sensor driver"); |
944 | MODULE_LICENSE("GPL"); |
945 |
Definitions
- sht3x_cmd_measure_single_hpm
- sht3x_cmd_measure_single_mpm
- sht3x_cmd_measure_single_lpm
- sht3x_cmd_measure_periodic_mode
- sht3x_cmd_break
- sht3x_cmd_heater_on
- sht3x_cmd_heater_off
- sht3x_cmd_read_status_reg
- sht3x_cmd_clear_status_reg
- sht3x_cmd_read_serial_number
- sht3x_chips
- sht3x_limits
- sht3x_repeatability
- sht3x_crc8_table
- periodic_measure_commands_hpm
- periodic_measure_commands_mpm
- periodic_measure_commands_lpm
- sht3x_limit_commands
- limit_commands
- mode_to_update_interval
- sht3x_channel_info
- sht3x_data
- get_mode_from_update_interval
- sht3x_read_from_command
- sht3x_extract_temperature
- sht3x_extract_humidity
- sht3x_update_client
- temp1_input_read
- humidity1_input_read
- limits_update
- temp1_limit_read
- humidity1_limit_read
- limit_write
- temp1_limit_write
- humidity1_limit_write
- sht3x_select_command
- status_register_read
- temp1_alarm_read
- humidity1_alarm_read
- heater_enable_show
- heater_enable_store
- update_interval_read
- update_interval_write
- repeatability_show
- repeatability_store
- sht3x_attrs
- sht3x_is_visible
- sht3x_read
- sht3x_write
- sht3x_serial_number_read
- sht3x_ops
- sht3x_chip_info
- sht3x_probe
- sht3x_ids
Improve your Profiling and Debugging skills
Find out more