aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHarald Geyer <harald@ccbib.org>2013-12-01 10:04:00 -0500
committerJonathan Cameron <jic23@kernel.org>2013-12-03 15:22:30 -0500
commit091a121b04547fab2045951aff6219318ede0560 (patch)
treed6753de7cf21bdc8de3a62952ce79cd0adc060a1 /drivers
parentac216aa290c48a5e9d7b9f2473abb977a175683a (diff)
iio: Add new driver dht11
This driver handles DHT11 and DHT22 sensors. Signed-off-by: Harald Geyer <harald@ccbib.org> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/iio/Kconfig1
-rw-r--r--drivers/iio/Makefile1
-rw-r--r--drivers/iio/humidity/Kconfig15
-rw-r--r--drivers/iio/humidity/Makefile5
-rw-r--r--drivers/iio/humidity/dht11.c294
5 files changed, 316 insertions, 0 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 90cf0cda50c4..a5ed88226276 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -65,6 +65,7 @@ source "drivers/iio/common/Kconfig"
65source "drivers/iio/dac/Kconfig" 65source "drivers/iio/dac/Kconfig"
66source "drivers/iio/frequency/Kconfig" 66source "drivers/iio/frequency/Kconfig"
67source "drivers/iio/gyro/Kconfig" 67source "drivers/iio/gyro/Kconfig"
68source "drivers/iio/humidity/Kconfig"
68source "drivers/iio/imu/Kconfig" 69source "drivers/iio/imu/Kconfig"
69source "drivers/iio/light/Kconfig" 70source "drivers/iio/light/Kconfig"
70source "drivers/iio/magnetometer/Kconfig" 71source "drivers/iio/magnetometer/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index bcf7e9e3b053..b3b50968b46b 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -18,6 +18,7 @@ obj-y += common/
18obj-y += dac/ 18obj-y += dac/
19obj-y += gyro/ 19obj-y += gyro/
20obj-y += frequency/ 20obj-y += frequency/
21obj-y += humidity/
21obj-y += imu/ 22obj-y += imu/
22obj-y += light/ 23obj-y += light/
23obj-y += magnetometer/ 24obj-y += magnetometer/
diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig
new file mode 100644
index 000000000000..463c4d9da79e
--- /dev/null
+++ b/drivers/iio/humidity/Kconfig
@@ -0,0 +1,15 @@
1#
2# humidity sensor drivers
3#
4menu "Humidity sensors"
5
6config DHT11
7 tristate "DHT11 (and compatible sensors) driver"
8 depends on GPIOLIB
9 help
10 This driver supports reading data via a single interrupt
11 generating GPIO line. Currently tested are DHT11 and DHT22.
12 Other sensors should work as well as long as they speak the
13 same protocol.
14
15endmenu
diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile
new file mode 100644
index 000000000000..d5d36c0c95f9
--- /dev/null
+++ b/drivers/iio/humidity/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for IIO humidity sensor drivers
3#
4
5obj-$(CONFIG_DHT11) += dht11.o
diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c
new file mode 100644
index 000000000000..d8771f546bf2
--- /dev/null
+++ b/drivers/iio/humidity/dht11.c
@@ -0,0 +1,294 @@
1/*
2 * DHT11/DHT22 bit banging GPIO driver
3 *
4 * Copyright (c) Harald Geyer <harald@ccbib.org>
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#include <linux/err.h>
18#include <linux/interrupt.h>
19#include <linux/device.h>
20#include <linux/kernel.h>
21#include <linux/printk.h>
22#include <linux/slab.h>
23#include <linux/of.h>
24#include <linux/of_device.h>
25#include <linux/sysfs.h>
26#include <linux/io.h>
27#include <linux/module.h>
28#include <linux/platform_device.h>
29#include <linux/wait.h>
30#include <linux/bitops.h>
31#include <linux/completion.h>
32#include <linux/delay.h>
33#include <linux/gpio.h>
34#include <linux/of_gpio.h>
35
36#include <linux/iio/iio.h>
37
38#define DRIVER_NAME "dht11"
39
40#define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */
41
42#define DHT11_EDGES_PREAMBLE 4
43#define DHT11_BITS_PER_READ 40
44#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1)
45
46/* Data transmission timing (nano seconds) */
47#define DHT11_START_TRANSMISSION 18 /* ms */
48#define DHT11_SENSOR_RESPONSE 80000
49#define DHT11_START_BIT 50000
50#define DHT11_DATA_BIT_LOW 27000
51#define DHT11_DATA_BIT_HIGH 70000
52
53struct dht11 {
54 struct device *dev;
55
56 int gpio;
57 int irq;
58
59 struct completion completion;
60
61 s64 timestamp;
62 int temperature;
63 int humidity;
64
65 /* num_edges: -1 means "no transmission in progress" */
66 int num_edges;
67 struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ];
68};
69
70static unsigned char dht11_decode_byte(int *timing, int threshold)
71{
72 unsigned char ret = 0;
73 int i;
74
75 for (i = 0; i < 8; ++i) {
76 ret <<= 1;
77 if (timing[i] >= threshold)
78 ++ret;
79 }
80
81 return ret;
82}
83
84static int dht11_decode(struct dht11 *dht11, int offset)
85{
86 int i, t, timing[DHT11_BITS_PER_READ], threshold,
87 timeres = DHT11_SENSOR_RESPONSE;
88 unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;
89
90 /* Calculate timestamp resolution */
91 for (i = 0; i < dht11->num_edges; ++i) {
92 t = dht11->edges[i].ts - dht11->edges[i-1].ts;
93 if (t > 0 && t < timeres)
94 timeres = t;
95 }
96 if (2*timeres > DHT11_DATA_BIT_HIGH) {
97 pr_err("dht11: timeresolution %d too bad for decoding\n",
98 timeres);
99 return -EIO;
100 }
101 threshold = DHT11_DATA_BIT_HIGH / timeres;
102 if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold)
103 pr_err("dht11: WARNING: decoding ambiguous\n");
104
105 /* scale down with timeres and check validity */
106 for (i = 0; i < DHT11_BITS_PER_READ; ++i) {
107 t = dht11->edges[offset + 2*i + 2].ts -
108 dht11->edges[offset + 2*i + 1].ts;
109 if (!dht11->edges[offset + 2*i + 1].value)
110 return -EIO; /* lost synchronisation */
111 timing[i] = t / timeres;
112 }
113
114 hum_int = dht11_decode_byte(timing, threshold);
115 hum_dec = dht11_decode_byte(&timing[8], threshold);
116 temp_int = dht11_decode_byte(&timing[16], threshold);
117 temp_dec = dht11_decode_byte(&timing[24], threshold);
118 checksum = dht11_decode_byte(&timing[32], threshold);
119
120 if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)
121 return -EIO;
122
123 dht11->timestamp = iio_get_time_ns();
124 if (hum_int < 20) { /* DHT22 */
125 dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *
126 ((temp_int & 0x80) ? -100 : 100);
127 dht11->humidity = ((hum_int << 8) + hum_dec) * 100;
128 } else if (temp_dec == 0 && hum_dec == 0) { /* DHT11 */
129 dht11->temperature = temp_int * 1000;
130 dht11->humidity = hum_int * 1000;
131 } else {
132 dev_err(dht11->dev,
133 "Don't know how to decode data: %d %d %d %d\n",
134 hum_int, hum_dec, temp_int, temp_dec);
135 return -EIO;
136 }
137
138 return 0;
139}
140
141static int dht11_read_raw(struct iio_dev *iio_dev,
142 const struct iio_chan_spec *chan,
143 int *val, int *val2, long m)
144{
145 struct dht11 *dht11 = iio_priv(iio_dev);
146 int ret;
147
148 if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) {
149 reinit_completion(&dht11->completion);
150
151 dht11->num_edges = 0;
152 ret = gpio_direction_output(dht11->gpio, 0);
153 if (ret)
154 goto err;
155 msleep(DHT11_START_TRANSMISSION);
156 ret = gpio_direction_input(dht11->gpio);
157 if (ret)
158 goto err;
159
160 ret = wait_for_completion_killable_timeout(&dht11->completion,
161 HZ);
162 if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {
163 dev_err(&iio_dev->dev,
164 "Only %d signal edges detected\n",
165 dht11->num_edges);
166 ret = -ETIMEDOUT;
167 }
168 if (ret < 0)
169 goto err;
170
171 ret = dht11_decode(dht11,
172 dht11->num_edges == DHT11_EDGES_PER_READ ?
173 DHT11_EDGES_PREAMBLE :
174 DHT11_EDGES_PREAMBLE - 2);
175 if (ret)
176 goto err;
177 }
178
179 ret = IIO_VAL_INT;
180 if (chan->type == IIO_TEMP)
181 *val = dht11->temperature;
182 else if (chan->type == IIO_HUMIDITYRELATIVE)
183 *val = dht11->humidity;
184 else
185 ret = -EINVAL;
186err:
187 dht11->num_edges = -1;
188 return ret;
189}
190
191static const struct iio_info dht11_iio_info = {
192 .driver_module = THIS_MODULE,
193 .read_raw = dht11_read_raw,
194};
195
196/*
197 * IRQ handler called on GPIO edges
198*/
199static irqreturn_t dht11_handle_irq(int irq, void *data)
200{
201 struct iio_dev *iio = data;
202 struct dht11 *dht11 = iio_priv(iio);
203
204 /* TODO: Consider making the handler safe for IRQ sharing */
205 if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {
206 dht11->edges[dht11->num_edges].ts = iio_get_time_ns();
207 dht11->edges[dht11->num_edges++].value =
208 gpio_get_value(dht11->gpio);
209
210 if (dht11->num_edges >= DHT11_EDGES_PER_READ)
211 complete(&dht11->completion);
212 }
213
214 return IRQ_HANDLED;
215}
216
217static const struct iio_chan_spec dht11_chan_spec[] = {
218 { .type = IIO_TEMP,
219 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), },
220 { .type = IIO_HUMIDITYRELATIVE,
221 .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }
222};
223
224static const struct of_device_id dht11_dt_ids[] = {
225 { .compatible = "dht11", },
226 { }
227};
228MODULE_DEVICE_TABLE(of, dht11_dt_ids);
229
230static int dht11_probe(struct platform_device *pdev)
231{
232 struct device *dev = &pdev->dev;
233 struct device_node *node = dev->of_node;
234 struct dht11 *dht11;
235 struct iio_dev *iio;
236 int ret;
237
238 iio = devm_iio_device_alloc(dev, sizeof(*dht11));
239 if (!iio) {
240 dev_err(dev, "Failed to allocate IIO device\n");
241 return -ENOMEM;
242 }
243
244 dht11 = iio_priv(iio);
245 dht11->dev = dev;
246
247 dht11->gpio = ret = of_get_gpio(node, 0);
248 if (ret < 0)
249 return ret;
250 ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name);
251 if (ret)
252 return ret;
253
254 dht11->irq = gpio_to_irq(dht11->gpio);
255 if (dht11->irq < 0) {
256 dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);
257 return -EINVAL;
258 }
259 ret = devm_request_irq(dev, dht11->irq, dht11_handle_irq,
260 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
261 pdev->name, iio);
262 if (ret)
263 return ret;
264
265 dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1;
266 dht11->num_edges = -1;
267
268 platform_set_drvdata(pdev, iio);
269
270 init_completion(&dht11->completion);
271 iio->name = pdev->name;
272 iio->dev.parent = &pdev->dev;
273 iio->info = &dht11_iio_info;
274 iio->modes = INDIO_DIRECT_MODE;
275 iio->channels = dht11_chan_spec;
276 iio->num_channels = ARRAY_SIZE(dht11_chan_spec);
277
278 return devm_iio_device_register(dev, iio);
279}
280
281static struct platform_driver dht11_driver = {
282 .driver = {
283 .name = DRIVER_NAME,
284 .owner = THIS_MODULE,
285 .of_match_table = dht11_dt_ids,
286 },
287 .probe = dht11_probe,
288};
289
290module_platform_driver(dht11_driver);
291
292MODULE_AUTHOR("Harald Geyer <harald@ccbib.org>");
293MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver");
294MODULE_LICENSE("GPL v2");