aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorUrs Fleisch <urs.fleisch@gmail.com>2011-01-07 02:15:39 -0500
committerGuenter Roeck <guenter.roeck@ericsson.com>2011-01-08 13:56:28 -0500
commit430400b86304ea729ba10f2966a8af67da60a37f (patch)
tree79abaa76d689a40923167103582bb11e69fd096c /drivers
parentc6c2c1636e30bcd26c6b0d208324055a03c5ab9c (diff)
hwmon: driver for Sensirion SHT21 humidity and temperature sensor
Signed-off-by: Urs Fleisch <urs.fleisch@sensirion.com> Acked-by: Jonathan Cameron <jic23@cam.ac.uk> Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/sht21.c307
3 files changed, 318 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a56f6adf3b76..0f09567257fd 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -734,6 +734,16 @@ config SENSORS_SHT15
734 This driver can also be built as a module. If so, the module 734 This driver can also be built as a module. If so, the module
735 will be called sht15. 735 will be called sht15.
736 736
737config SENSORS_SHT21
738 tristate "Sensiron humidity and temperature sensors. SHT21 and compat."
739 depends on I2C
740 help
741 If you say yes here you get support for the Sensiron SHT21, SHT25
742 humidity and temperature sensors.
743
744 This driver can also be built as a module. If so, the module
745 will be called sht21.
746
737config SENSORS_S3C 747config SENSORS_S3C
738 tristate "Samsung built-in ADC" 748 tristate "Samsung built-in ADC"
739 depends on S3C_ADC 749 depends on S3C_ADC
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 2479b3da272c..20e74086e681 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -90,6 +90,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
90obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o 90obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
91obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o 91obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o
92obj-$(CONFIG_SENSORS_SHT15) += sht15.o 92obj-$(CONFIG_SENSORS_SHT15) += sht15.o
93obj-$(CONFIG_SENSORS_SHT21) += sht21.o
93obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o 94obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
94obj-$(CONFIG_SENSORS_SMM665) += smm665.o 95obj-$(CONFIG_SENSORS_SMM665) += smm665.o
95obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o 96obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c
new file mode 100644
index 000000000000..1c8c9812f244
--- /dev/null
+++ b/drivers/hwmon/sht21.c
@@ -0,0 +1,307 @@
1/* Sensirion SHT21 humidity and temperature sensor driver
2 *
3 * Copyright (C) 2010 Urs Fleisch <urs.fleisch@sensirion.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Data sheet available (5/2010) at
20 * http://www.sensirion.com/en/pdf/product_information/Datasheet-humidity-sensor-SHT21.pdf
21 */
22
23#include <linux/module.h>
24#include <linux/init.h>
25#include <linux/slab.h>
26#include <linux/i2c.h>
27#include <linux/hwmon.h>
28#include <linux/hwmon-sysfs.h>
29#include <linux/err.h>
30#include <linux/mutex.h>
31#include <linux/device.h>
32
33/* I2C command bytes */
34#define SHT21_TRIG_T_MEASUREMENT_HM 0xe3
35#define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5
36
37/**
38 * struct sht21 - SHT21 device specific data
39 * @hwmon_dev: device registered with hwmon
40 * @lock: mutex to protect measurement values
41 * @valid: only 0 before first measurement is taken
42 * @last_update: time of last update (jiffies)
43 * @temperature: cached temperature measurement value
44 * @humidity: cached humidity measurement value
45 */
46struct sht21 {
47 struct device *hwmon_dev;
48 struct mutex lock;
49 char valid;
50 unsigned long last_update;
51 int temperature;
52 int humidity;
53};
54
55/**
56 * sht21_temp_ticks_to_millicelsius() - convert raw temperature ticks to
57 * milli celsius
58 * @ticks: temperature ticks value received from sensor
59 */
60static inline int sht21_temp_ticks_to_millicelsius(int ticks)
61{
62 ticks &= ~0x0003; /* clear status bits */
63 /*
64 * Formula T = -46.85 + 175.72 * ST / 2^16 from data sheet 6.2,
65 * optimized for integer fixed point (3 digits) arithmetic
66 */
67 return ((21965 * ticks) >> 13) - 46850;
68}
69
70/**
71 * sht21_rh_ticks_to_per_cent_mille() - convert raw humidity ticks to
72 * one-thousandths of a percent relative humidity
73 * @ticks: humidity ticks value received from sensor
74 */
75static inline int sht21_rh_ticks_to_per_cent_mille(int ticks)
76{
77 ticks &= ~0x0003; /* clear status bits */
78 /*
79 * Formula RH = -6 + 125 * SRH / 2^16 from data sheet 6.1,
80 * optimized for integer fixed point (3 digits) arithmetic
81 */
82 return ((15625 * ticks) >> 13) - 6000;
83}
84
85/**
86 * sht21_read_word_data() - read word from register
87 * @client: I2C client device
88 * @reg: I2C command byte
89 *
90 * Returns value, negative errno on error.
91 */
92static inline int sht21_read_word_data(struct i2c_client *client, u8 reg)
93{
94 int ret = i2c_smbus_read_word_data(client, reg);
95 if (ret < 0)
96 return ret;
97 /*
98 * SMBus specifies low byte first, but the SHT21 returns MSB
99 * first, so we have to swab16 the values
100 */
101 return swab16(ret);
102}
103
104/**
105 * sht21_update_measurements() - get updated measurements from device
106 * @client: I2C client device
107 *
108 * Returns 0 on success, else negative errno.
109 */
110static int sht21_update_measurements(struct i2c_client *client)
111{
112 int ret = 0;
113 struct sht21 *sht21 = i2c_get_clientdata(client);
114
115 mutex_lock(&sht21->lock);
116 /*
117 * Data sheet 2.4:
118 * SHT2x should not be active for more than 10% of the time - e.g.
119 * maximum two measurements per second at 12bit accuracy shall be made.
120 */
121 if (time_after(jiffies, sht21->last_update + HZ / 2) || !sht21->valid) {
122 ret = sht21_read_word_data(client, SHT21_TRIG_T_MEASUREMENT_HM);
123 if (ret < 0)
124 goto out;
125 sht21->temperature = sht21_temp_ticks_to_millicelsius(ret);
126 ret = sht21_read_word_data(client,
127 SHT21_TRIG_RH_MEASUREMENT_HM);
128 if (ret < 0)
129 goto out;
130 sht21->humidity = sht21_rh_ticks_to_per_cent_mille(ret);
131 sht21->last_update = jiffies;
132 sht21->valid = 1;
133 }
134out:
135 mutex_unlock(&sht21->lock);
136
137 return ret >= 0 ? 0 : ret;
138}
139
140/**
141 * sht21_show_temperature() - show temperature measurement value in sysfs
142 * @dev: device
143 * @attr: device attribute
144 * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
145 *
146 * Will be called on read access to temp1_input sysfs attribute.
147 * Returns number of bytes written into buffer, negative errno on error.
148 */
149static ssize_t sht21_show_temperature(struct device *dev,
150 struct device_attribute *attr,
151 char *buf)
152{
153 struct i2c_client *client = to_i2c_client(dev);
154 struct sht21 *sht21 = i2c_get_clientdata(client);
155 int ret = sht21_update_measurements(client);
156 if (ret < 0)
157 return ret;
158 return sprintf(buf, "%d\n", sht21->temperature);
159}
160
161/**
162 * sht21_show_humidity() - show humidity measurement value in sysfs
163 * @dev: device
164 * @attr: device attribute
165 * @buf: sysfs buffer (PAGE_SIZE) where measurement values are written to
166 *
167 * Will be called on read access to humidity1_input sysfs attribute.
168 * Returns number of bytes written into buffer, negative errno on error.
169 */
170static ssize_t sht21_show_humidity(struct device *dev,
171 struct device_attribute *attr,
172 char *buf)
173{
174 struct i2c_client *client = to_i2c_client(dev);
175 struct sht21 *sht21 = i2c_get_clientdata(client);
176 int ret = sht21_update_measurements(client);
177 if (ret < 0)
178 return ret;
179 return sprintf(buf, "%d\n", sht21->humidity);
180}
181
182/* sysfs attributes */
183static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature,
184 NULL, 0);
185static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity,
186 NULL, 0);
187
188static struct attribute *sht21_attributes[] = {
189 &sensor_dev_attr_temp1_input.dev_attr.attr,
190 &sensor_dev_attr_humidity1_input.dev_attr.attr,
191 NULL
192};
193
194static const struct attribute_group sht21_attr_group = {
195 .attrs = sht21_attributes,
196};
197
198/**
199 * sht21_probe() - probe device
200 * @client: I2C client device
201 * @id: device ID
202 *
203 * Called by the I2C core when an entry in the ID table matches a
204 * device's name.
205 * Returns 0 on success.
206 */
207static int __devinit sht21_probe(struct i2c_client *client,
208 const struct i2c_device_id *id)
209{
210 struct sht21 *sht21;
211 int err;
212
213 if (!i2c_check_functionality(client->adapter,
214 I2C_FUNC_SMBUS_WORD_DATA)) {
215 dev_err(&client->dev,
216 "adapter does not support SMBus word transactions\n");
217 return -ENODEV;
218 }
219
220 sht21 = kzalloc(sizeof(*sht21), GFP_KERNEL);
221 if (!sht21) {
222 dev_dbg(&client->dev, "kzalloc failed\n");
223 return -ENOMEM;
224 }
225 i2c_set_clientdata(client, sht21);
226
227 mutex_init(&sht21->lock);
228
229 err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group);
230 if (err) {
231 dev_dbg(&client->dev, "could not create sysfs files\n");
232 goto fail_free;
233 }
234 sht21->hwmon_dev = hwmon_device_register(&client->dev);
235 if (IS_ERR(sht21->hwmon_dev)) {
236 dev_dbg(&client->dev, "unable to register hwmon device\n");
237 err = PTR_ERR(sht21->hwmon_dev);
238 goto fail_remove_sysfs;
239 }
240
241 dev_info(&client->dev, "initialized\n");
242
243 return 0;
244
245fail_remove_sysfs:
246 sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
247fail_free:
248 kfree(sht21);
249
250 return err;
251}
252
253/**
254 * sht21_remove() - remove device
255 * @client: I2C client device
256 */
257static int __devexit sht21_remove(struct i2c_client *client)
258{
259 struct sht21 *sht21 = i2c_get_clientdata(client);
260
261 hwmon_device_unregister(sht21->hwmon_dev);
262 sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
263 kfree(sht21);
264
265 return 0;
266}
267
268/* Device ID table */
269static const struct i2c_device_id sht21_id[] = {
270 { "sht21", 0 },
271 { }
272};
273MODULE_DEVICE_TABLE(i2c, sht21_id);
274
275static struct i2c_driver sht21_driver = {
276 .driver.name = "sht21",
277 .probe = sht21_probe,
278 .remove = __devexit_p(sht21_remove),
279 .id_table = sht21_id,
280};
281
282/**
283 * sht21_init() - initialize driver
284 *
285 * Called when kernel is booted or module is inserted.
286 * Returns 0 on success.
287 */
288static int __init sht21_init(void)
289{
290 return i2c_add_driver(&sht21_driver);
291}
292module_init(sht21_init);
293
294/**
295 * sht21_init() - clean up driver
296 *
297 * Called when module is removed.
298 */
299static void __exit sht21_exit(void)
300{
301 i2c_del_driver(&sht21_driver);
302}
303module_exit(sht21_exit);
304
305MODULE_AUTHOR("Urs Fleisch <urs.fleisch@sensirion.com>");
306MODULE_DESCRIPTION("Sensirion SHT21 humidity and temperature sensor driver");
307MODULE_LICENSE("GPL");