aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Frey <david.frey@sensirion.com>2016-06-02 03:59:11 -0400
committerGuenter Roeck <linux@roeck-us.net>2016-06-27 21:58:03 -0400
commit7c84f7f80d6fcea36246b793d06c3555ca53ddcd (patch)
tree28469d58b195ac6a9c957b14a3c2f1ae65bfd60a
parent76b5808e8cb9d8be214a1bbf613e19b6e3ebb3fb (diff)
hwmon: add support for Sensirion SHT3x sensors
This driver implements support for the Sensirion SHT3x-DIS chip, a humidity and temperature sensor. Temperature is measured in degrees celsius, relative humidity is expressed as a percentage. In the sysfs interface, all values are scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500. Signed-off-by: Pascal Sachs <pascal.sachs@sensirion.com> [groeck: Fixed 'Variable length array is used' gcc warning] Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r--Documentation/hwmon/sht3x72
-rw-r--r--drivers/hwmon/Kconfig11
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/sht3x.c725
-rw-r--r--include/linux/platform_data/sht3x.h25
5 files changed, 834 insertions, 0 deletions
diff --git a/Documentation/hwmon/sht3x b/Documentation/hwmon/sht3x
new file mode 100644
index 000000000000..f5aa633ed383
--- /dev/null
+++ b/Documentation/hwmon/sht3x
@@ -0,0 +1,72 @@
1Kernel driver sht3x
2===================
3
4Supported chips:
5 * Sensirion SHT3x-DIS
6 Prefix: 'sht3x'
7 Addresses scanned: none
8 Datasheet: http://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/Humidity/Sensirion_Humidity_Datasheet_SHT3x_DIS.pdf
9
10Author:
11 David Frey <david.frey@sensirion.com>
12 Pascal Sachs <pascal.sachs@sensirion.com>
13
14Description
15-----------
16
17This driver implements support for the Sensirion SHT3x-DIS chip, a humidity
18and temperature sensor. Temperature is measured in degrees celsius, relative
19humidity is expressed as a percentage. In the sysfs interface, all values are
20scaled by 1000, i.e. the value for 31.5 degrees celsius is 31500.
21
22The device communicates with the I2C protocol. Sensors can have the I2C
23addresses 0x44 or 0x45, depending on the wiring. See
24Documentation/i2c/instantiating-devices for methods to instantiate the device.
25
26There are two options configurable by means of sht3x_platform_data:
271. blocking (pull the I2C clock line down while performing the measurement) or
28 non-blocking mode. Blocking mode will guarantee the fastest result but
29 the I2C bus will be busy during that time. By default, non-blocking mode
30 is used. Make sure clock-stretching works properly on your device if you
31 want to use blocking mode.
322. high or low accuracy. High accuracy is used by default and using it is
33 strongly recommended.
34
35The sht3x sensor supports a single shot mode as well as 5 periodic measure
36modes, which can be controlled with the update_interval sysfs interface.
37The allowed update_interval in milliseconds are as follows:
38 * 0 single shot mode
39 * 2000 0.5 Hz periodic measurement
40 * 1000 1 Hz periodic measurement
41 * 500 2 Hz periodic measurement
42 * 250 4 Hz periodic measurement
43 * 100 10 Hz periodic measurement
44
45In the periodic measure mode, the sensor automatically triggers a measurement
46with the configured update interval on the chip. When a temperature or humidity
47reading exceeds the configured limits, the alert attribute is set to 1 and
48the alert pin on the sensor is set to high.
49When the temperature and humidity readings move back between the hysteresis
50values, the alert bit is set to 0 and the alert pin on the sensor is set to
51low.
52
53sysfs-Interface
54---------------
55
56temp1_input: temperature input
57humidity1_input: humidity input
58temp1_max: temperature max value
59temp1_max_hyst: temperature hysteresis value for max limit
60humidity1_max: humidity max value
61humidity1_max_hyst: humidity hysteresis value for max limit
62temp1_min: temperature min value
63temp1_min_hyst: temperature hysteresis value for min limit
64humidity1_min: humidity min value
65humidity1_min_hyst: humidity hysteresis value for min limit
66temp1_alarm: alarm flag is set to 1 if the temperature is outside the
67 configured limits. Alarm only works in periodic measure mode
68humidity1_alarm: alarm flag is set to 1 if the humidity is outside the
69 configured limits. Alarm only works in periodic measure mode
70update_interval: update interval, 0 for single shot, interval in msec
71 for periodic measurement. If the interval is not supported
72 by the sensor, the next faster interval is chosen
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index ff940075bb90..e0be99a4615c 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1265,6 +1265,17 @@ config SENSORS_SHT21
1265 This driver can also be built as a module. If so, the module 1265 This driver can also be built as a module. If so, the module
1266 will be called sht21. 1266 will be called sht21.
1267 1267
1268config SENSORS_SHT3x
1269 tristate "Sensiron humidity and temperature sensors. SHT3x and compat."
1270 depends on I2C
1271 select CRC8
1272 help
1273 If you say yes here you get support for the Sensiron SHT30 and SHT31
1274 humidity and temperature sensors.
1275
1276 This driver can also be built as a module. If so, the module
1277 will be called sht3x.
1278
1268config SENSORS_SHTC1 1279config SENSORS_SHTC1
1269 tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." 1280 tristate "Sensiron humidity and temperature sensors. SHTC1 and compat."
1270 depends on I2C 1281 depends on I2C
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2ef5b7c4c54f..406b18b995b3 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -138,6 +138,7 @@ obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
138obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o 138obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o
139obj-$(CONFIG_SENSORS_SHT15) += sht15.o 139obj-$(CONFIG_SENSORS_SHT15) += sht15.o
140obj-$(CONFIG_SENSORS_SHT21) += sht21.o 140obj-$(CONFIG_SENSORS_SHT21) += sht21.o
141obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o
141obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o 142obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o
142obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o 143obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
143obj-$(CONFIG_SENSORS_SMM665) += smm665.o 144obj-$(CONFIG_SENSORS_SMM665) += smm665.o
diff --git a/drivers/hwmon/sht3x.c b/drivers/hwmon/sht3x.c
new file mode 100644
index 000000000000..707a3f85385b
--- /dev/null
+++ b/drivers/hwmon/sht3x.c
@@ -0,0 +1,725 @@
1/* Sensirion SHT3x-DIS humidity and temperature sensor driver.
2 * The SHT3x comes in many different versions, this driver is for the
3 * I2C version only.
4 *
5 * Copyright (C) 2016 Sensirion AG, Switzerland
6 * Author: David Frey <david.frey@sensirion.com>
7 * Author: Pascal Sachs <pascal.sachs@sensirion.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 */
20
21#include <asm/page.h>
22#include <linux/crc8.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/hwmon.h>
26#include <linux/hwmon-sysfs.h>
27#include <linux/i2c.h>
28#include <linux/init.h>
29#include <linux/kernel.h>
30#include <linux/module.h>
31#include <linux/slab.h>
32#include <linux/jiffies.h>
33#include <linux/platform_data/sht3x.h>
34
35/* commands (high precision mode) */
36static const unsigned char sht3x_cmd_measure_blocking_hpm[] = { 0x2c, 0x06 };
37static const unsigned char sht3x_cmd_measure_nonblocking_hpm[] = { 0x24, 0x00 };
38
39/* commands (low power mode) */
40static const unsigned char sht3x_cmd_measure_blocking_lpm[] = { 0x2c, 0x10 };
41static const unsigned char sht3x_cmd_measure_nonblocking_lpm[] = { 0x24, 0x16 };
42
43/* commands for periodic mode */
44static const unsigned char sht3x_cmd_measure_periodic_mode[] = { 0xe0, 0x00 };
45static const unsigned char sht3x_cmd_break[] = { 0x30, 0x93 };
46
47/* other commands */
48static const unsigned char sht3x_cmd_read_status_reg[] = { 0xf3, 0x2d };
49static const unsigned char sht3x_cmd_clear_status_reg[] = { 0x30, 0x41 };
50
51/* delays for non-blocking i2c commands, both in us */
52#define SHT3X_NONBLOCKING_WAIT_TIME_HPM 15000
53#define SHT3X_NONBLOCKING_WAIT_TIME_LPM 4000
54
55#define SHT3X_WORD_LEN 2
56#define SHT3X_CMD_LENGTH 2
57#define SHT3X_CRC8_LEN 1
58#define SHT3X_RESPONSE_LENGTH 6
59#define SHT3X_CRC8_POLYNOMIAL 0x31
60#define SHT3X_CRC8_INIT 0xFF
61#define SHT3X_MIN_TEMPERATURE -45000
62#define SHT3X_MAX_TEMPERATURE 130000
63#define SHT3X_MIN_HUMIDITY 0
64#define SHT3X_MAX_HUMIDITY 100000
65
66enum sht3x_chips {
67 sht3x,
68 sts3x,
69};
70
71enum sht3x_limits {
72 limit_max = 0,
73 limit_max_hyst,
74 limit_min,
75 limit_min_hyst,
76};
77
78DECLARE_CRC8_TABLE(sht3x_crc8_table);
79
80/* periodic measure commands (high precision mode) */
81static const char periodic_measure_commands_hpm[][SHT3X_CMD_LENGTH] = {
82 /* 0.5 measurements per second */
83 {0x20, 0x32},
84 /* 1 measurements per second */
85 {0x21, 0x30},
86 /* 2 measurements per second */
87 {0x22, 0x36},
88 /* 4 measurements per second */
89 {0x23, 0x34},
90 /* 10 measurements per second */
91 {0x27, 0x37},
92};
93
94/* periodic measure commands (low power mode) */
95static const char periodic_measure_commands_lpm[][SHT3X_CMD_LENGTH] = {
96 /* 0.5 measurements per second */
97 {0x20, 0x2f},
98 /* 1 measurements per second */
99 {0x21, 0x2d},
100 /* 2 measurements per second */
101 {0x22, 0x2b},
102 /* 4 measurements per second */
103 {0x23, 0x29},
104 /* 10 measurements per second */
105 {0x27, 0x2a},
106};
107
108struct sht3x_limit_commands {
109 const char read_command[SHT3X_CMD_LENGTH];
110 const char write_command[SHT3X_CMD_LENGTH];
111};
112
113static const struct sht3x_limit_commands limit_commands[] = {
114 /* temp1_max, humidity1_max */
115 [limit_max] = { {0xe1, 0x1f}, {0x61, 0x1d} },
116 /* temp_1_max_hyst, humidity1_max_hyst */
117 [limit_max_hyst] = { {0xe1, 0x14}, {0x61, 0x16} },
118 /* temp1_min, humidity1_min */
119 [limit_min] = { {0xe1, 0x02}, {0x61, 0x00} },
120 /* temp_1_min_hyst, humidity1_min_hyst */
121 [limit_min_hyst] = { {0xe1, 0x09}, {0x61, 0x0B} },
122};
123
124#define SHT3X_NUM_LIMIT_CMD ARRAY_SIZE(limit_commands)
125
126static const u16 mode_to_update_interval[] = {
127 0,
128 2000,
129 1000,
130 500,
131 250,
132 100,
133};
134
135struct sht3x_data {
136 struct i2c_client *client;
137 struct mutex i2c_lock; /* lock for sending i2c commands */
138 struct mutex data_lock; /* lock for updating driver data */
139
140 u8 mode;
141 const unsigned char *command;
142 u32 wait_time; /* in us*/
143 unsigned long last_update; /* last update in periodic mode*/
144
145 struct sht3x_platform_data setup;
146
147 /*
148 * cached values for temperature and humidity and limits
149 * the limits arrays have the following order:
150 * max, max_hyst, min, min_hyst
151 */
152 int temperature;
153 int temperature_limits[SHT3X_NUM_LIMIT_CMD];
154 u32 humidity;
155 u32 humidity_limits[SHT3X_NUM_LIMIT_CMD];
156};
157
158static u8 get_mode_from_update_interval(u16 value)
159{
160 size_t index;
161 u8 number_of_modes = ARRAY_SIZE(mode_to_update_interval);
162
163 if (value == 0)
164 return 0;
165
166 /* find next faster update interval */
167 for (index = 1; index < number_of_modes; index++) {
168 if (mode_to_update_interval[index] <= value)
169 return index;
170 }
171
172 return number_of_modes - 1;
173}
174
175static int sht3x_read_from_command(struct i2c_client *client,
176 struct sht3x_data *data,
177 const char *command,
178 char *buf, int length, u32 wait_time)
179{
180 int ret;
181
182 mutex_lock(&data->i2c_lock);
183 ret = i2c_master_send(client, command, SHT3X_CMD_LENGTH);
184
185 if (ret != SHT3X_CMD_LENGTH) {
186 ret = ret < 0 ? ret : -EIO;
187 goto out;
188 }
189
190 if (wait_time)
191 usleep_range(wait_time, wait_time + 1000);
192
193 ret = i2c_master_recv(client, buf, length);
194 if (ret != length) {
195 ret = ret < 0 ? ret : -EIO;
196 goto out;
197 }
198
199 ret = 0;
200out:
201 mutex_unlock(&data->i2c_lock);
202 return ret;
203}
204
205static int sht3x_extract_temperature(u16 raw)
206{
207 /*
208 * From datasheet:
209 * T = -45 + 175 * ST / 2^16
210 * Adapted for integer fixed point (3 digit) arithmetic.
211 */
212 return ((21875 * (int)raw) >> 13) - 45000;
213}
214
215static u32 sht3x_extract_humidity(u16 raw)
216{
217 /*
218 * From datasheet:
219 * RH = 100 * SRH / 2^16
220 * Adapted for integer fixed point (3 digit) arithmetic.
221 */
222 return (12500 * (u32)raw) >> 13;
223}
224
225static struct sht3x_data *sht3x_update_client(struct device *dev)
226{
227 struct sht3x_data *data = dev_get_drvdata(dev);
228 struct i2c_client *client = data->client;
229 u16 interval_ms = mode_to_update_interval[data->mode];
230 unsigned long interval_jiffies = msecs_to_jiffies(interval_ms);
231 unsigned char buf[SHT3X_RESPONSE_LENGTH];
232 u16 val;
233 int ret = 0;
234
235 mutex_lock(&data->data_lock);
236 /*
237 * Only update cached readings once per update interval in periodic
238 * mode. In single shot mode the sensor measures values on demand, so
239 * every time the sysfs interface is called, a measurement is triggered.
240 * In periodic mode however, the measurement process is handled
241 * internally by the sensor and reading out sensor values only makes
242 * sense if a new reading is available.
243 */
244 if (time_after(jiffies, data->last_update + interval_jiffies)) {
245 ret = sht3x_read_from_command(client, data, data->command, buf,
246 sizeof(buf), data->wait_time);
247 if (ret)
248 goto out;
249
250 val = be16_to_cpup((__be16 *)buf);
251 data->temperature = sht3x_extract_temperature(val);
252 val = be16_to_cpup((__be16 *)(buf + 3));
253 data->humidity = sht3x_extract_humidity(val);
254 data->last_update = jiffies;
255 }
256
257out:
258 mutex_unlock(&data->data_lock);
259 if (ret)
260 return ERR_PTR(ret);
261
262 return data;
263}
264
265/* sysfs attributes */
266static ssize_t temp1_input_show(struct device *dev,
267 struct device_attribute *attr, char *buf)
268{
269 struct sht3x_data *data = sht3x_update_client(dev);
270
271 if (IS_ERR(data))
272 return PTR_ERR(data);
273
274 return sprintf(buf, "%d\n", data->temperature);
275}
276
277static ssize_t humidity1_input_show(struct device *dev,
278 struct device_attribute *attr, char *buf)
279{
280 struct sht3x_data *data = sht3x_update_client(dev);
281
282 if (IS_ERR(data))
283 return PTR_ERR(data);
284
285 return sprintf(buf, "%u\n", data->humidity);
286}
287
288/*
289 * limits_update must only be called from probe or with data_lock held
290 */
291static int limits_update(struct sht3x_data *data)
292{
293 int ret;
294 u8 index;
295 int temperature;
296 u32 humidity;
297 u16 raw;
298 char buffer[SHT3X_RESPONSE_LENGTH];
299 const struct sht3x_limit_commands *commands;
300 struct i2c_client *client = data->client;
301
302 for (index = 0; index < SHT3X_NUM_LIMIT_CMD; index++) {
303 commands = &limit_commands[index];
304 ret = sht3x_read_from_command(client, data,
305 commands->read_command, buffer,
306 SHT3X_RESPONSE_LENGTH, 0);
307
308 if (ret)
309 return ret;
310
311 raw = be16_to_cpup((__be16 *)buffer);
312 temperature = sht3x_extract_temperature((raw & 0x01ff) << 7);
313 humidity = sht3x_extract_humidity(raw & 0xfe00);
314 data->temperature_limits[index] = temperature;
315 data->humidity_limits[index] = humidity;
316 }
317
318 return ret;
319}
320
321static ssize_t temp1_limit_show(struct device *dev,
322 struct device_attribute *attr,
323 char *buf)
324{
325 struct sht3x_data *data = dev_get_drvdata(dev);
326 u8 index = to_sensor_dev_attr(attr)->index;
327 int temperature_limit = data->temperature_limits[index];
328
329 return scnprintf(buf, PAGE_SIZE, "%d\n", temperature_limit);
330}
331
332static ssize_t humidity1_limit_show(struct device *dev,
333 struct device_attribute *attr,
334 char *buf)
335{
336 struct sht3x_data *data = dev_get_drvdata(dev);
337 u8 index = to_sensor_dev_attr(attr)->index;
338 u32 humidity_limit = data->humidity_limits[index];
339
340 return scnprintf(buf, PAGE_SIZE, "%u\n", humidity_limit);
341}
342
343/*
344 * limit_store must only be called with data_lock held
345 */
346static size_t limit_store(struct device *dev,
347 size_t count,
348 u8 index,
349 int temperature,
350 u32 humidity)
351{
352 char buffer[SHT3X_CMD_LENGTH + SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
353 char *position = buffer;
354 int ret;
355 u16 raw;
356 struct sht3x_data *data = dev_get_drvdata(dev);
357 struct i2c_client *client = data->client;
358 const struct sht3x_limit_commands *commands;
359
360 commands = &limit_commands[index];
361
362 memcpy(position, commands->write_command, SHT3X_CMD_LENGTH);
363 position += SHT3X_CMD_LENGTH;
364 /*
365 * ST = (T + 45) / 175 * 2^16
366 * SRH = RH / 100 * 2^16
367 * adapted for fixed point arithmetic and packed the same as
368 * in limit_show()
369 */
370 raw = ((u32)(temperature + 45000) * 24543) >> (16 + 7);
371 raw |= ((humidity * 42950) >> 16) & 0xfe00;
372
373 *((__be16 *)position) = cpu_to_be16(raw);
374 position += SHT3X_WORD_LEN;
375 *position = crc8(sht3x_crc8_table,
376 position - SHT3X_WORD_LEN,
377 SHT3X_WORD_LEN,
378 SHT3X_CRC8_INIT);
379
380 mutex_lock(&data->i2c_lock);
381 ret = i2c_master_send(client, buffer, sizeof(buffer));
382 mutex_unlock(&data->i2c_lock);
383
384 if (ret != sizeof(buffer))
385 return ret < 0 ? ret : -EIO;
386
387 data->temperature_limits[index] = temperature;
388 data->humidity_limits[index] = humidity;
389 return count;
390}
391
392static ssize_t temp1_limit_store(struct device *dev,
393 struct device_attribute *attr,
394 const char *buf,
395 size_t count)
396{
397 int temperature;
398 int ret;
399 struct sht3x_data *data = dev_get_drvdata(dev);
400 u8 index = to_sensor_dev_attr(attr)->index;
401
402 ret = kstrtoint(buf, 0, &temperature);
403 if (ret)
404 return ret;
405
406 temperature = clamp_val(temperature, SHT3X_MIN_TEMPERATURE,
407 SHT3X_MAX_TEMPERATURE);
408 mutex_lock(&data->data_lock);
409 ret = limit_store(dev, count, index, temperature,
410 data->humidity_limits[index]);
411 mutex_unlock(&data->data_lock);
412
413 return ret;
414}
415
416static ssize_t humidity1_limit_store(struct device *dev,
417 struct device_attribute *attr,
418 const char *buf,
419 size_t count)
420{
421 u32 humidity;
422 int ret;
423 struct sht3x_data *data = dev_get_drvdata(dev);
424 u8 index = to_sensor_dev_attr(attr)->index;
425
426 ret = kstrtou32(buf, 0, &humidity);
427 if (ret)
428 return ret;
429
430 humidity = clamp_val(humidity, SHT3X_MIN_HUMIDITY, SHT3X_MAX_HUMIDITY);
431 mutex_lock(&data->data_lock);
432 ret = limit_store(dev, count, index, data->temperature_limits[index],
433 humidity);
434 mutex_unlock(&data->data_lock);
435
436 return ret;
437}
438
439static void sht3x_select_command(struct sht3x_data *data)
440{
441 /*
442 * In blocking mode (clock stretching mode) the I2C bus
443 * is blocked for other traffic, thus the call to i2c_master_recv()
444 * will wait until the data is ready. For non blocking mode, we
445 * have to wait ourselves.
446 */
447 if (data->mode > 0) {
448 data->command = sht3x_cmd_measure_periodic_mode;
449 data->wait_time = 0;
450 } else if (data->setup.blocking_io) {
451 data->command = data->setup.high_precision ?
452 sht3x_cmd_measure_blocking_hpm :
453 sht3x_cmd_measure_blocking_lpm;
454 data->wait_time = 0;
455 } else {
456 if (data->setup.high_precision) {
457 data->command = sht3x_cmd_measure_nonblocking_hpm;
458 data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_HPM;
459 } else {
460 data->command = sht3x_cmd_measure_nonblocking_lpm;
461 data->wait_time = SHT3X_NONBLOCKING_WAIT_TIME_LPM;
462 }
463 }
464}
465
466static int status_register_read(struct device *dev,
467 struct device_attribute *attr,
468 char *buffer, int length)
469{
470 int ret;
471 struct sht3x_data *data = dev_get_drvdata(dev);
472 struct i2c_client *client = data->client;
473
474 ret = sht3x_read_from_command(client, data, sht3x_cmd_read_status_reg,
475 buffer, length, 0);
476
477 return ret;
478}
479
480static ssize_t temp1_alarm_show(struct device *dev,
481 struct device_attribute *attr,
482 char *buf)
483{
484 char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
485 int ret;
486
487 ret = status_register_read(dev, attr, buffer,
488 SHT3X_WORD_LEN + SHT3X_CRC8_LEN);
489 if (ret)
490 return ret;
491
492 return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x04));
493}
494
495static ssize_t humidity1_alarm_show(struct device *dev,
496 struct device_attribute *attr,
497 char *buf)
498{
499 char buffer[SHT3X_WORD_LEN + SHT3X_CRC8_LEN];
500 int ret;
501
502 ret = status_register_read(dev, attr, buffer,
503 SHT3X_WORD_LEN + SHT3X_CRC8_LEN);
504 if (ret)
505 return ret;
506
507 return scnprintf(buf, PAGE_SIZE, "%d\n", !!(buffer[0] & 0x08));
508}
509
510static ssize_t update_interval_show(struct device *dev,
511 struct device_attribute *attr,
512 char *buf)
513{
514 struct sht3x_data *data = dev_get_drvdata(dev);
515
516 return scnprintf(buf, PAGE_SIZE, "%u\n",
517 mode_to_update_interval[data->mode]);
518}
519
520static ssize_t update_interval_store(struct device *dev,
521 struct device_attribute *attr,
522 const char *buf,
523 size_t count)
524{
525 u16 update_interval;
526 u8 mode;
527 int ret;
528 const char *command;
529 struct sht3x_data *data = dev_get_drvdata(dev);
530 struct i2c_client *client = data->client;
531
532 ret = kstrtou16(buf, 0, &update_interval);
533 if (ret)
534 return ret;
535
536 mode = get_mode_from_update_interval(update_interval);
537
538 mutex_lock(&data->data_lock);
539 /* mode did not change */
540 if (mode == data->mode) {
541 mutex_unlock(&data->data_lock);
542 return count;
543 }
544
545 mutex_lock(&data->i2c_lock);
546 /*
547 * Abort periodic measure mode.
548 * To do any changes to the configuration while in periodic mode, we
549 * have to send a break command to the sensor, which then falls back
550 * to single shot (mode = 0).
551 */
552 if (data->mode > 0) {
553 ret = i2c_master_send(client, sht3x_cmd_break,
554 SHT3X_CMD_LENGTH);
555 if (ret != SHT3X_CMD_LENGTH)
556 goto out;
557 data->mode = 0;
558 }
559
560 if (mode > 0) {
561 if (data->setup.high_precision)
562 command = periodic_measure_commands_hpm[mode - 1];
563 else
564 command = periodic_measure_commands_lpm[mode - 1];
565
566 /* select mode */
567 ret = i2c_master_send(client, command, SHT3X_CMD_LENGTH);
568 if (ret != SHT3X_CMD_LENGTH)
569 goto out;
570 }
571
572 /* select mode and command */
573 data->mode = mode;
574 sht3x_select_command(data);
575
576out:
577 mutex_unlock(&data->i2c_lock);
578 mutex_unlock(&data->data_lock);
579 if (ret != SHT3X_CMD_LENGTH)
580 return ret < 0 ? ret : -EIO;
581
582 return count;
583}
584
585static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp1_input_show, NULL, 0);
586static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, humidity1_input_show,
587 NULL, 0);
588static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
589 temp1_limit_show, temp1_limit_store,
590 limit_max);
591static SENSOR_DEVICE_ATTR(humidity1_max, S_IRUGO | S_IWUSR,
592 humidity1_limit_show, humidity1_limit_store,
593 limit_max);
594static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
595 temp1_limit_show, temp1_limit_store,
596 limit_max_hyst);
597static SENSOR_DEVICE_ATTR(humidity1_max_hyst, S_IRUGO | S_IWUSR,
598 humidity1_limit_show, humidity1_limit_store,
599 limit_max_hyst);
600static SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR,
601 temp1_limit_show, temp1_limit_store,
602 limit_min);
603static SENSOR_DEVICE_ATTR(humidity1_min, S_IRUGO | S_IWUSR,
604 humidity1_limit_show, humidity1_limit_store,
605 limit_min);
606static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO | S_IWUSR,
607 temp1_limit_show, temp1_limit_store,
608 limit_min_hyst);
609static SENSOR_DEVICE_ATTR(humidity1_min_hyst, S_IRUGO | S_IWUSR,
610 humidity1_limit_show, humidity1_limit_store,
611 limit_min_hyst);
612static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, temp1_alarm_show, NULL, 0);
613static SENSOR_DEVICE_ATTR(humidity1_alarm, S_IRUGO, humidity1_alarm_show,
614 NULL, 0);
615static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
616 update_interval_show, update_interval_store, 0);
617
618static struct attribute *sht3x_attrs[] = {
619 &sensor_dev_attr_temp1_input.dev_attr.attr,
620 &sensor_dev_attr_humidity1_input.dev_attr.attr,
621 &sensor_dev_attr_temp1_max.dev_attr.attr,
622 &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
623 &sensor_dev_attr_humidity1_max.dev_attr.attr,
624 &sensor_dev_attr_humidity1_max_hyst.dev_attr.attr,
625 &sensor_dev_attr_temp1_min.dev_attr.attr,
626 &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
627 &sensor_dev_attr_humidity1_min.dev_attr.attr,
628 &sensor_dev_attr_humidity1_min_hyst.dev_attr.attr,
629 &sensor_dev_attr_temp1_alarm.dev_attr.attr,
630 &sensor_dev_attr_humidity1_alarm.dev_attr.attr,
631 &sensor_dev_attr_update_interval.dev_attr.attr,
632 NULL
633};
634
635static struct attribute *sts3x_attrs[] = {
636 &sensor_dev_attr_temp1_input.dev_attr.attr,
637 NULL
638};
639
640ATTRIBUTE_GROUPS(sht3x);
641ATTRIBUTE_GROUPS(sts3x);
642
643static int sht3x_probe(struct i2c_client *client,
644 const struct i2c_device_id *id)
645{
646 int ret;
647 struct sht3x_data *data;
648 struct device *hwmon_dev;
649 struct i2c_adapter *adap = client->adapter;
650 struct device *dev = &client->dev;
651 const struct attribute_group **attribute_groups;
652
653 /*
654 * we require full i2c support since the sht3x uses multi-byte read and
655 * writes as well as multi-byte commands which are not supported by
656 * the smbus protocol
657 */
658 if (!i2c_check_functionality(adap, I2C_FUNC_I2C))
659 return -ENODEV;
660
661 ret = i2c_master_send(client, sht3x_cmd_clear_status_reg,
662 SHT3X_CMD_LENGTH);
663 if (ret != SHT3X_CMD_LENGTH)
664 return ret < 0 ? ret : -ENODEV;
665
666 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
667 if (!data)
668 return -ENOMEM;
669
670 data->setup.blocking_io = false;
671 data->setup.high_precision = true;
672 data->mode = 0;
673 data->last_update = 0;
674 data->client = client;
675 crc8_populate_msb(sht3x_crc8_table, SHT3X_CRC8_POLYNOMIAL);
676
677 if (client->dev.platform_data)
678 data->setup = *(struct sht3x_platform_data *)dev->platform_data;
679
680 sht3x_select_command(data);
681
682 mutex_init(&data->i2c_lock);
683 mutex_init(&data->data_lock);
684
685 ret = limits_update(data);
686 if (ret)
687 return ret;
688
689 if (id->driver_data == sts3x)
690 attribute_groups = sts3x_groups;
691 else
692 attribute_groups = sht3x_groups;
693
694 hwmon_dev = devm_hwmon_device_register_with_groups(dev,
695 client->name,
696 data,
697 attribute_groups);
698
699 if (IS_ERR(hwmon_dev))
700 dev_dbg(dev, "unable to register hwmon device\n");
701
702 return PTR_ERR_OR_ZERO(hwmon_dev);
703}
704
705/* device ID table */
706static const struct i2c_device_id sht3x_ids[] = {
707 {"sht3x", sht3x},
708 {"sts3x", sts3x},
709 {}
710};
711
712MODULE_DEVICE_TABLE(i2c, sht3x_ids);
713
714static struct i2c_driver sht3x_i2c_driver = {
715 .driver.name = "sht3x",
716 .probe = sht3x_probe,
717 .id_table = sht3x_ids,
718};
719
720module_i2c_driver(sht3x_i2c_driver);
721
722MODULE_AUTHOR("David Frey <david.frey@sensirion.com>");
723MODULE_AUTHOR("Pascal Sachs <pascal.sachs@sensirion.com>");
724MODULE_DESCRIPTION("Sensirion SHT3x humidity and temperature sensor driver");
725MODULE_LICENSE("GPL");
diff --git a/include/linux/platform_data/sht3x.h b/include/linux/platform_data/sht3x.h
new file mode 100644
index 000000000000..2e5eea358194
--- /dev/null
+++ b/include/linux/platform_data/sht3x.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2016 Sensirion AG, Switzerland
3 * Author: David Frey <david.frey@sensirion.com>
4 * Author: Pascal Sachs <pascal.sachs@sensirion.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#ifndef __SHT3X_H_
19#define __SHT3X_H_
20
21struct sht3x_platform_data {
22 bool blocking_io;
23 bool high_precision;
24};
25#endif /* __SHT3X_H_ */