]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/gpio/gpioths.c
dwc: Rename if_dwc.h to dwc1000_reg.h
[FreeBSD/FreeBSD.git] / sys / dev / gpio / gpioths.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2016 Michael Zhilin <mizhka@freebsd.org> All rights reserved.
5  * Copyright (c) 2019 Ian Lepore <ian@freebsd.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*
30  * GPIOTHS - Temp/Humidity sensor over GPIO.
31  *
32  * This is driver for Temperature & Humidity sensor which provides digital
33  * output over single-wire protocol from embedded 8-bit microcontroller.
34  * Note that it uses a custom single-wire protocol, it is not 1-wire(tm).
35  * 
36  * This driver supports the following chips:
37  *   DHT11:  Temp   0c to 50c +-2.0c, Humidity 20% to  90% +-5%
38  *   DHT12:  Temp -20c to 60c +-0.5c, Humidity 20% to  95% +-5%
39  *   DHT21:  Temp -40c to 80c +-0.3c, Humidity  0% to 100% +-3%
40  *   DHT22:  Temp -40c to 80c +-0.3c, Humidity  0% to 100% +-2%
41  *   AM2301: Same as DHT21, but also supports i2c interface.
42  *   AM2302: Same as DHT22, but also supports i2c interface.
43  *
44  * Temp/Humidity sensor can't be discovered automatically, please specify hints
45  * as part of loader or kernel configuration:
46  *      hint.gpioths.0.at="gpiobus0"
47  *      hint.gpioths.0.pins=<PIN>
48  *
49  * Or configure via FDT data.
50  */
51
52 #include <sys/cdefs.h>
53 #include <sys/param.h>
54 #include <sys/kernel.h>
55 #include <sys/bus.h>
56 #include <sys/gpio.h>
57 #include <sys/module.h>
58 #include <sys/errno.h>
59 #include <sys/systm.h>
60 #include <sys/sysctl.h>
61 #include <sys/taskqueue.h>
62
63 #include <dev/gpio/gpiobusvar.h>
64
65 #ifdef FDT
66 #include <dev/ofw/ofw_bus.h>
67 #include <dev/ofw/ofw_bus_subr.h>
68
69 static struct ofw_compat_data compat_data[] = {
70         {"dht11",  true},
71         {NULL,     false}
72 };
73 OFWBUS_PNP_INFO(compat_data);
74 SIMPLEBUS_PNP_INFO(compat_data);
75 #endif /* FDT */
76
77 #define PIN_IDX 0                       /* Use the first/only configured pin. */
78
79 #define GPIOTHS_POLLTIME        5       /* in seconds */
80
81 #define GPIOTHS_DHT_STARTCYCLE  20000   /* 20ms = 20000us */
82 #define GPIOTHS_DHT_TIMEOUT     1000    /* 1ms = 1000us */
83 #define GPIOTHS_DHT_CYCLES      41
84 #define GPIOTHS_DHT_ONEBYTEMASK 0xFF
85
86 struct gpioths_softc {
87         device_t                 dev;
88         gpio_pin_t               pin;
89         int                      temp;
90         int                      hum;
91         int                      fails;
92         struct timeout_task      task;
93         bool                     detaching;
94 };
95
96 static int
97 gpioths_probe(device_t dev)
98 {
99         int rv;
100
101         /*
102          * By default we only bid to attach if specifically added by our parent
103          * (usually via hint.gpioths.#.at=busname).  On FDT systems we bid as
104          * the default driver based on being configured in the FDT data.
105          */
106         rv = BUS_PROBE_NOWILDCARD;
107
108 #ifdef FDT
109         if (ofw_bus_status_okay(dev) &&
110             ofw_bus_search_compatible(dev, compat_data)->ocd_data)
111                 rv = BUS_PROBE_DEFAULT;
112 #endif
113
114         device_set_desc(dev, "DHT11/DHT22 Temperature and Humidity Sensor");
115
116         return (rv);
117 }
118
119 static int
120 gpioths_dht_timeuntil(struct gpioths_softc *sc, bool lev, uint32_t *time)
121 {
122         bool            cur_level;
123         int             i;
124
125         for (i = 0; i < GPIOTHS_DHT_TIMEOUT; i++) {
126                 gpio_pin_is_active(sc->pin, &cur_level);
127                 if (cur_level == lev) {
128                         if (time != NULL)
129                                 *time = i;
130                         return (0);
131                 }
132                 DELAY(1);
133         }
134
135         /* Timeout */
136         return (ETIMEDOUT);
137 }
138
139 static void
140 gpioths_dht_initread(struct gpioths_softc *sc)
141 {
142
143         /*
144          * According to specifications we need to drive the data line low for at
145          * least 20ms then drive it high, to wake up the chip and signal it to
146          * send a measurement. After sending this start signal, we switch the
147          * pin back to input so the device can begin talking to us.
148          */
149         gpio_pin_setflags(sc->pin, GPIO_PIN_OUTPUT);
150         gpio_pin_set_active(sc->pin, false);
151         pause_sbt("gpioths", ustosbt(GPIOTHS_DHT_STARTCYCLE), C_PREL(2), 0);
152         gpio_pin_set_active(sc->pin, true);
153         gpio_pin_setflags(sc->pin, GPIO_PIN_INPUT);
154 }
155
156 static int
157 gpioths_dht_readbytes(struct gpioths_softc *sc)
158 {
159         uint32_t                 calibrations[GPIOTHS_DHT_CYCLES];
160         uint32_t                 intervals[GPIOTHS_DHT_CYCLES];
161         uint32_t                 err, avglen, value;
162         uint8_t                  crc, calc;
163         int                      i, negmul, offset, size, tmphi, tmplo;
164
165         gpioths_dht_initread(sc);
166         
167         err = gpioths_dht_timeuntil(sc, false, NULL);
168         if (err) {
169                 device_printf(sc->dev, "err(START) = %d\n", err);
170                 goto error;
171         }
172
173         /* reading - 41 cycles */
174         for (i = 0; i < GPIOTHS_DHT_CYCLES; i++) {
175                 err = gpioths_dht_timeuntil(sc, true, &calibrations[i]);
176                 if (err) {
177                         device_printf(sc->dev, "err(CAL, %d) = %d\n", i, err);
178                         goto error;
179                 }
180                 err = gpioths_dht_timeuntil(sc, false, &intervals[i]);
181                 if (err) {
182                         device_printf(sc->dev, "err(INTERVAL, %d) = %d\n", i, err);
183                         goto error;
184                 }
185         }
186
187         /* Calculate average data calibration cycle length */
188         avglen = 0;
189         for (i = 1; i < GPIOTHS_DHT_CYCLES; i++)
190                 avglen += calibrations[i];
191
192         avglen = avglen / (GPIOTHS_DHT_CYCLES - 1);
193
194         /* Calculate data */
195         value = 0;
196         offset = 1;
197         size = sizeof(value) * 8;
198         for (i = offset; i < size + offset; i++) {
199                 value <<= 1;
200                 if (intervals[i] > avglen)
201                         value += 1;
202         }
203
204         /* Calculate CRC */
205         crc = 0;
206         offset = sizeof(value) * 8 + 1;
207         size = sizeof(crc) * 8;
208         for (i = offset;  i < size + offset; i++) {
209                 crc <<= 1;
210                 if (intervals[i] > avglen)
211                         crc += 1;
212         }
213
214         calc = 0;
215         for (i = 0; i < sizeof(value); i++)
216                 calc += (value >> (8*i)) & GPIOTHS_DHT_ONEBYTEMASK;
217
218 #ifdef GPIOTHS_DEBUG
219         /* Debug bits */
220         for (i = 0; i < GPIOTHS_DHT_CYCLES; i++)
221                 device_printf(sc->dev, "%d: %d %d\n", i, calibrations[i],
222                     intervals[i]);
223
224         device_printf(sc->dev, "len=%d, data=%x, crc=%x/%x\n", avglen, value, crc,
225             calc);
226 #endif /* GPIOTHS_DEBUG */
227
228         /* CRC check */
229         if (calc != crc) {
230                 err = -1;
231                 goto error;
232         }
233
234         /*
235          * For DHT11/12, the values are split into 8 bits of integer and 8 bits
236          * of fractional tenths.  On DHT11 the fraction bytes are always zero.
237          * On DHT12 the sign bit is in the high bit of the fraction byte.
238          *  - DHT11: 0HHHHHHH 00000000 00TTTTTT 00000000
239          *  - DHT12: 0HHHHHHH 0000hhhh 00TTTTTT s000tttt
240          *
241          * For DHT21/21, the values are are encoded in 16 bits each, with the
242          * temperature sign bit in the high bit.  The values are tenths of a
243          * degree C and tenths of a percent RH.
244          *  - DHT21: 000000HH HHHHHHHH s00000TT TTTTTTTT
245          *  - DHT22: 000000HH HHHHHHHH s00000TT TTTTTTTT
246          *
247          * For all devices, some bits are always zero because of the range of
248          * values supported by the device.
249          *
250          * We figure out how to decode things based on the high byte of the
251          * humidity.  A DHT21/22 cannot report a value greater than 3 in
252          * the upper bits of its 16-bit humidity.  A DHT11/12 should not report
253          * a value lower than 20.  To allow for the possibility that a device
254          * could report a value slightly out of its sensitivity range, we split
255          * the difference and say if the value is greater than 10 it must be a
256          * DHT11/12 (that would be a humidity over 256% on a DHT21/22).
257          */
258 #define DK_OFFSET 2731 /* Offset between K and C, in decikelvins. */
259         if ((value >> 24) > 10) {
260                 /* DHT11 or DHT12 */
261                 tmphi = (value >> 8) & 0x3f;
262                 tmplo = value & 0x0f;
263                 negmul = (value & 0x80) ? -1 : 1;
264                 sc->temp = DK_OFFSET + (negmul * (tmphi * 10 + tmplo));
265                 sc->hum = (value >> 24) & 0x7f;
266         } else {
267                 /* DHT21 or DHT22 */
268                 negmul = (value & 0x8000) ? -1 : 1;
269                 sc->temp = DK_OFFSET + (negmul * (value & 0x03ff));
270                 sc->hum = ((value >> 16) & 0x03ff) / 10;
271         }
272
273         sc->fails = 0;
274
275 #ifdef GPIOTHS_DEBUG
276         /* Debug bits */
277         device_printf(dev, "fails=%d, temp=%d, hum=%d\n", sc->fails,
278             sc->temp, sc->hum);
279 #endif /* GPIOTHS_DEBUG */
280
281         return (0);
282 error:
283         sc->fails++;
284         return (err);
285 }
286
287 static void
288 gpioths_poll(void *arg, int pending __unused)
289 {
290         struct gpioths_softc    *sc;
291
292         sc = (struct gpioths_softc *)arg;
293
294         gpioths_dht_readbytes(sc);
295         if (!sc->detaching)
296                 taskqueue_enqueue_timeout_sbt(taskqueue_thread, &sc->task,
297                     GPIOTHS_POLLTIME * SBT_1S, 0, C_PREL(3));
298 }
299
300 static int
301 gpioths_attach(device_t dev)
302 {
303         struct gpioths_softc    *sc;
304         struct sysctl_ctx_list  *ctx;
305         struct sysctl_oid       *tree;
306         int err;
307
308         sc = device_get_softc(dev);
309         ctx = device_get_sysctl_ctx(dev);
310         tree = device_get_sysctl_tree(dev);
311
312         sc->dev = dev;
313
314         TIMEOUT_TASK_INIT(taskqueue_thread, &sc->task, 0, gpioths_poll, sc);
315
316 #ifdef FDT
317         /* Try to configure our pin from fdt data on fdt-based systems. */
318         err = gpio_pin_get_by_ofw_idx(dev, ofw_bus_get_node(dev), PIN_IDX,
319             &sc->pin);
320 #else
321         err = ENOENT;
322 #endif
323         /*
324          * If we didn't get configured by fdt data and our parent is gpiobus,
325          * see if we can be configured by the bus (allows hinted attachment even
326          * on fdt-based systems).
327          */
328         if (err != 0 &&
329             strcmp("gpiobus", device_get_name(device_get_parent(dev))) == 0)
330                 err = gpio_pin_get_by_child_index(dev, PIN_IDX, &sc->pin);
331
332         /* If we didn't get configured by either method, whine and punt. */
333         if (err != 0) {
334                 device_printf(sc->dev,
335                     "cannot acquire gpio pin (config error)\n");
336                 return (err);
337         }
338
339         /*
340          * Ensure we have control of our pin, and preset the data line to its
341          * idle condition (high).  Leave the line in input mode, relying on the
342          * external pullup to keep the line high while idle.
343          */
344         err = gpio_pin_setflags(sc->pin, GPIO_PIN_OUTPUT);
345         if (err != 0) {
346                 device_printf(dev, "gpio_pin_setflags(OUT) = %d\n", err);
347                 return (err);
348         }
349         err = gpio_pin_set_active(sc->pin, true);
350         if (err != 0) {
351                 device_printf(dev, "gpio_pin_set_active(false) = %d\n", err);
352                 return (err);
353         }
354         err = gpio_pin_setflags(sc->pin, GPIO_PIN_INPUT);
355         if (err != 0) {
356                 device_printf(dev, "gpio_pin_setflags(IN) = %d\n", err);
357                 return (err);
358         }
359
360         /* 
361          * Do an initial read so we have correct values for reporting before
362          * registering the sysctls that can access those values.  This also
363          * schedules the periodic polling the driver does every few seconds to
364          * update the sysctl variables.
365          */
366         gpioths_poll(sc, 0);
367
368         sysctl_add_oid(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "temperature",                             \
369             CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE,
370             &sc->temp, 0, sysctl_handle_int, "IK", "temperature", NULL);
371
372         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "humidity",
373             CTLFLAG_RD, &sc->hum, 0, "relative humidity(%)");
374
375         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "fails",
376             CTLFLAG_RD, &sc->fails, 0,
377             "failures since last successful read");
378
379         return (0);
380 }
381
382 static int
383 gpioths_detach(device_t dev)
384 {
385         struct gpioths_softc    *sc;
386
387         sc = device_get_softc(dev);
388         gpio_pin_release(sc->pin);
389         sc->detaching = true;
390         while (taskqueue_cancel_timeout(taskqueue_thread, &sc->task, NULL) != 0)
391                 taskqueue_drain_timeout(taskqueue_thread, &sc->task);
392
393         return (0);
394 }
395
396 /* Driver bits */
397 static device_method_t gpioths_methods[] = {
398         /* Device interface */
399         DEVMETHOD(device_probe,                 gpioths_probe),
400         DEVMETHOD(device_attach,                gpioths_attach),
401         DEVMETHOD(device_detach,                gpioths_detach),
402
403         DEVMETHOD_END
404 };
405
406 DEFINE_CLASS_0(gpioths, gpioths_driver, gpioths_methods, sizeof(struct gpioths_softc));
407
408 #ifdef FDT
409 DRIVER_MODULE(gpioths, simplebus, gpioths_driver, 0, 0);
410 #endif
411
412 DRIVER_MODULE(gpioths, gpiobus, gpioths_driver, 0, 0);
413 MODULE_DEPEND(gpioths, gpiobus, 1, 1, 1);