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