1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
34#define SHT21_TRIG_T_MEASUREMENT_HM 0xe3
35#define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5
36
37
38
39
40
41
42
43
44
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
57
58
59
60static inline int sht21_temp_ticks_to_millicelsius(int ticks)
61{
62 ticks &= ~0x0003;
63
64
65
66
67 return ((21965 * ticks) >> 13) - 46850;
68}
69
70
71
72
73
74
75static inline int sht21_rh_ticks_to_per_cent_mille(int ticks)
76{
77 ticks &= ~0x0003;
78
79
80
81
82 return ((15625 * ticks) >> 13) - 6000;
83}
84
85
86
87
88
89
90
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
99
100
101 return swab16(ret);
102}
103
104
105
106
107
108
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
118
119
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
142
143
144
145
146
147
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
163
164
165
166
167
168
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
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
200
201
202
203
204
205
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
255
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
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
284
285
286
287
288static int __init sht21_init(void)
289{
290 return i2c_add_driver(&sht21_driver);
291}
292module_init(sht21_init);
293
294
295
296
297
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");
308