xref: /freebsd/sys/dev/gpio/gpioths.c (revision 069ac184)
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/param.h>
53 #include <sys/kernel.h>
54 #include <sys/bus.h>
55 #include <sys/gpio.h>
56 #include <sys/module.h>
57 #include <sys/errno.h>
58 #include <sys/systm.h>
59 #include <sys/sysctl.h>
60 #include <sys/taskqueue.h>
61 
62 #include <dev/gpio/gpiobusvar.h>
63 
64 #ifdef FDT
65 #include <dev/ofw/ofw_bus.h>
66 #include <dev/ofw/ofw_bus_subr.h>
67 
68 static struct ofw_compat_data compat_data[] = {
69 	{"dht11",  true},
70 	{NULL,     false}
71 };
72 OFWBUS_PNP_INFO(compat_data);
73 SIMPLEBUS_PNP_INFO(compat_data);
74 #endif /* FDT */
75 
76 #define	PIN_IDX 0			/* Use the first/only configured pin. */
77 
78 #define	GPIOTHS_POLLTIME	5	/* in seconds */
79 
80 #define	GPIOTHS_DHT_STARTCYCLE	20000	/* 20ms = 20000us */
81 #define	GPIOTHS_DHT_TIMEOUT	1000	/* 1ms = 1000us */
82 #define	GPIOTHS_DHT_CYCLES	41
83 #define	GPIOTHS_DHT_ONEBYTEMASK	0xFF
84 
85 struct gpioths_softc {
86 	device_t		 dev;
87 	gpio_pin_t		 pin;
88 	int			 temp;
89 	int			 hum;
90 	int			 fails;
91 	struct timeout_task	 task;
92 	bool			 detaching;
93 };
94 
95 static int
96 gpioths_probe(device_t dev)
97 {
98 	int rv;
99 
100 	/*
101 	 * By default we only bid to attach if specifically added by our parent
102 	 * (usually via hint.gpioths.#.at=busname).  On FDT systems we bid as
103 	 * the default driver based on being configured in the FDT data.
104 	 */
105 	rv = BUS_PROBE_NOWILDCARD;
106 
107 #ifdef FDT
108 	if (ofw_bus_status_okay(dev) &&
109 	    ofw_bus_search_compatible(dev, compat_data)->ocd_data)
110 		rv = BUS_PROBE_DEFAULT;
111 #endif
112 
113 	device_set_desc(dev, "DHT11/DHT22 Temperature and Humidity Sensor");
114 
115 	return (rv);
116 }
117 
118 static int
119 gpioths_dht_timeuntil(struct gpioths_softc *sc, bool lev, uint32_t *time)
120 {
121 	bool		cur_level;
122 	int		i;
123 
124 	for (i = 0; i < GPIOTHS_DHT_TIMEOUT; i++) {
125 		gpio_pin_is_active(sc->pin, &cur_level);
126 		if (cur_level == lev) {
127 			if (time != NULL)
128 				*time = i;
129 			return (0);
130 		}
131 		DELAY(1);
132 	}
133 
134 	/* Timeout */
135 	return (ETIMEDOUT);
136 }
137 
138 static void
139 gpioths_dht_initread(struct gpioths_softc *sc)
140 {
141 
142 	/*
143 	 * According to specifications we need to drive the data line low for at
144 	 * least 20ms then drive it high, to wake up the chip and signal it to
145 	 * send a measurement. After sending this start signal, we switch the
146 	 * pin back to input so the device can begin talking to us.
147 	 */
148 	gpio_pin_setflags(sc->pin, GPIO_PIN_OUTPUT);
149 	gpio_pin_set_active(sc->pin, false);
150 	pause_sbt("gpioths", ustosbt(GPIOTHS_DHT_STARTCYCLE), C_PREL(2), 0);
151 	gpio_pin_set_active(sc->pin, true);
152 	gpio_pin_setflags(sc->pin, GPIO_PIN_INPUT);
153 }
154 
155 static int
156 gpioths_dht_readbytes(struct gpioths_softc *sc)
157 {
158 	uint32_t		 calibrations[GPIOTHS_DHT_CYCLES];
159 	uint32_t		 intervals[GPIOTHS_DHT_CYCLES];
160 	uint32_t		 err, avglen, value;
161 	uint8_t			 crc, calc;
162 	int			 i, negmul, offset, size, tmphi, tmplo;
163 
164 	gpioths_dht_initread(sc);
165 
166 	err = gpioths_dht_timeuntil(sc, false, NULL);
167 	if (err) {
168 		device_printf(sc->dev, "err(START) = %d\n", err);
169 		goto error;
170 	}
171 
172 	/* reading - 41 cycles */
173 	for (i = 0; i < GPIOTHS_DHT_CYCLES; i++) {
174 		err = gpioths_dht_timeuntil(sc, true, &calibrations[i]);
175 		if (err) {
176 			device_printf(sc->dev, "err(CAL, %d) = %d\n", i, err);
177 			goto error;
178 		}
179 		err = gpioths_dht_timeuntil(sc, false, &intervals[i]);
180 		if (err) {
181 			device_printf(sc->dev, "err(INTERVAL, %d) = %d\n", i, err);
182 			goto error;
183 		}
184 	}
185 
186 	/* Calculate average data calibration cycle length */
187 	avglen = 0;
188 	for (i = 1; i < GPIOTHS_DHT_CYCLES; i++)
189 		avglen += calibrations[i];
190 
191 	avglen = avglen / (GPIOTHS_DHT_CYCLES - 1);
192 
193 	/* Calculate data */
194 	value = 0;
195 	offset = 1;
196 	size = sizeof(value) * 8;
197 	for (i = offset; i < size + offset; i++) {
198 		value <<= 1;
199 		if (intervals[i] > avglen)
200 			value += 1;
201 	}
202 
203 	/* Calculate CRC */
204 	crc = 0;
205 	offset = sizeof(value) * 8 + 1;
206 	size = sizeof(crc) * 8;
207 	for (i = offset;  i < size + offset; i++) {
208 		crc <<= 1;
209 		if (intervals[i] > avglen)
210 			crc += 1;
211 	}
212 
213 	calc = 0;
214 	for (i = 0; i < sizeof(value); i++)
215 		calc += (value >> (8*i)) & GPIOTHS_DHT_ONEBYTEMASK;
216 
217 #ifdef GPIOTHS_DEBUG
218 	/* Debug bits */
219 	for (i = 0; i < GPIOTHS_DHT_CYCLES; i++)
220 		device_printf(sc->dev, "%d: %d %d\n", i, calibrations[i],
221 		    intervals[i]);
222 
223 	device_printf(sc->dev, "len=%d, data=%x, crc=%x/%x\n", avglen, value, crc,
224 	    calc);
225 #endif /* GPIOTHS_DEBUG */
226 
227 	/* CRC check */
228 	if (calc != crc) {
229 		err = -1;
230 		goto error;
231 	}
232 
233 	/*
234 	 * For DHT11/12, the values are split into 8 bits of integer and 8 bits
235 	 * of fractional tenths.  On DHT11 the fraction bytes are always zero.
236 	 * On DHT12 the sign bit is in the high bit of the fraction byte.
237 	 *  - DHT11: 0HHHHHHH 00000000 00TTTTTT 00000000
238 	 *  - DHT12: 0HHHHHHH 0000hhhh 00TTTTTT s000tttt
239 	 *
240 	 * For DHT21/21, the values are are encoded in 16 bits each, with the
241 	 * temperature sign bit in the high bit.  The values are tenths of a
242 	 * degree C and tenths of a percent RH.
243 	 *  - DHT21: 000000HH HHHHHHHH s00000TT TTTTTTTT
244 	 *  - DHT22: 000000HH HHHHHHHH s00000TT TTTTTTTT
245 	 *
246 	 * For all devices, some bits are always zero because of the range of
247 	 * values supported by the device.
248 	 *
249 	 * We figure out how to decode things based on the high byte of the
250 	 * humidity.  A DHT21/22 cannot report a value greater than 3 in
251 	 * the upper bits of its 16-bit humidity.  A DHT11/12 should not report
252 	 * a value lower than 20.  To allow for the possibility that a device
253 	 * could report a value slightly out of its sensitivity range, we split
254 	 * the difference and say if the value is greater than 10 it must be a
255 	 * DHT11/12 (that would be a humidity over 256% on a DHT21/22).
256 	 */
257 #define	DK_OFFSET 2731 /* Offset between K and C, in decikelvins. */
258 	if ((value >> 24) > 10) {
259 		/* DHT11 or DHT12 */
260 		tmphi = (value >> 8) & 0x3f;
261 		tmplo = value & 0x0f;
262 		negmul = (value & 0x80) ? -1 : 1;
263 		sc->temp = DK_OFFSET + (negmul * (tmphi * 10 + tmplo));
264 		sc->hum = (value >> 24) & 0x7f;
265 	} else {
266                 /* DHT21 or DHT22 */
267 		negmul = (value & 0x8000) ? -1 : 1;
268 		sc->temp = DK_OFFSET + (negmul * (value & 0x03ff));
269 		sc->hum = ((value >> 16) & 0x03ff) / 10;
270 	}
271 
272 	sc->fails = 0;
273 
274 #ifdef GPIOTHS_DEBUG
275 	/* Debug bits */
276 	device_printf(dev, "fails=%d, temp=%d, hum=%d\n", sc->fails,
277 	    sc->temp, sc->hum);
278 #endif /* GPIOTHS_DEBUG */
279 
280 	return (0);
281 error:
282 	sc->fails++;
283 	return (err);
284 }
285 
286 static void
287 gpioths_poll(void *arg, int pending __unused)
288 {
289 	struct gpioths_softc	*sc;
290 
291 	sc = (struct gpioths_softc *)arg;
292 
293 	gpioths_dht_readbytes(sc);
294 	if (!sc->detaching)
295 		taskqueue_enqueue_timeout_sbt(taskqueue_thread, &sc->task,
296 		    GPIOTHS_POLLTIME * SBT_1S, 0, C_PREL(3));
297 }
298 
299 static int
300 gpioths_attach(device_t dev)
301 {
302 	struct gpioths_softc	*sc;
303 	struct sysctl_ctx_list	*ctx;
304 	struct sysctl_oid	*tree;
305 	int err;
306 
307 	sc = device_get_softc(dev);
308 	ctx = device_get_sysctl_ctx(dev);
309 	tree = device_get_sysctl_tree(dev);
310 
311 	sc->dev = dev;
312 
313 	TIMEOUT_TASK_INIT(taskqueue_thread, &sc->task, 0, gpioths_poll, sc);
314 
315 #ifdef FDT
316 	/* Try to configure our pin from fdt data on fdt-based systems. */
317 	err = gpio_pin_get_by_ofw_idx(dev, ofw_bus_get_node(dev), PIN_IDX,
318 	    &sc->pin);
319 #else
320 	err = ENOENT;
321 #endif
322 	/*
323 	 * If we didn't get configured by fdt data and our parent is gpiobus,
324 	 * see if we can be configured by the bus (allows hinted attachment even
325 	 * on fdt-based systems).
326 	 */
327 	if (err != 0 &&
328 	    strcmp("gpiobus", device_get_name(device_get_parent(dev))) == 0)
329 		err = gpio_pin_get_by_child_index(dev, PIN_IDX, &sc->pin);
330 
331 	/* If we didn't get configured by either method, whine and punt. */
332 	if (err != 0) {
333 		device_printf(sc->dev,
334 		    "cannot acquire gpio pin (config error)\n");
335 		return (err);
336 	}
337 
338 	/*
339 	 * Ensure we have control of our pin, and preset the data line to its
340 	 * idle condition (high).  Leave the line in input mode, relying on the
341 	 * external pullup to keep the line high while idle.
342 	 */
343 	err = gpio_pin_setflags(sc->pin, GPIO_PIN_OUTPUT);
344 	if (err != 0) {
345 		device_printf(dev, "gpio_pin_setflags(OUT) = %d\n", err);
346 		return (err);
347 	}
348 	err = gpio_pin_set_active(sc->pin, true);
349 	if (err != 0) {
350 		device_printf(dev, "gpio_pin_set_active(false) = %d\n", err);
351 		return (err);
352 	}
353 	err = gpio_pin_setflags(sc->pin, GPIO_PIN_INPUT);
354 	if (err != 0) {
355 		device_printf(dev, "gpio_pin_setflags(IN) = %d\n", err);
356 		return (err);
357 	}
358 
359 	/*
360 	 * Do an initial read so we have correct values for reporting before
361 	 * registering the sysctls that can access those values.  This also
362 	 * schedules the periodic polling the driver does every few seconds to
363 	 * update the sysctl variables.
364 	 */
365 	gpioths_poll(sc, 0);
366 
367 	sysctl_add_oid(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "temperature",				\
368 	    CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE,
369 	    &sc->temp, 0, sysctl_handle_int, "IK", "temperature", NULL);
370 
371 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "humidity",
372 	    CTLFLAG_RD, &sc->hum, 0, "relative humidity(%)");
373 
374 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "fails",
375 	    CTLFLAG_RD, &sc->fails, 0,
376 	    "failures since last successful read");
377 
378 	return (0);
379 }
380 
381 static int
382 gpioths_detach(device_t dev)
383 {
384 	struct gpioths_softc	*sc;
385 
386 	sc = device_get_softc(dev);
387 	gpio_pin_release(sc->pin);
388 	sc->detaching = true;
389 	while (taskqueue_cancel_timeout(taskqueue_thread, &sc->task, NULL) != 0)
390 		taskqueue_drain_timeout(taskqueue_thread, &sc->task);
391 
392 	return (0);
393 }
394 
395 /* Driver bits */
396 static device_method_t gpioths_methods[] = {
397 	/* Device interface */
398 	DEVMETHOD(device_probe,			gpioths_probe),
399 	DEVMETHOD(device_attach,		gpioths_attach),
400 	DEVMETHOD(device_detach,		gpioths_detach),
401 
402 	DEVMETHOD_END
403 };
404 
405 DEFINE_CLASS_0(gpioths, gpioths_driver, gpioths_methods, sizeof(struct gpioths_softc));
406 
407 #ifdef FDT
408 DRIVER_MODULE(gpioths, simplebus, gpioths_driver, 0, 0);
409 #endif
410 
411 DRIVER_MODULE(gpioths, gpiobus, gpioths_driver, 0, 0);
412 MODULE_DEPEND(gpioths, gpiobus, 1, 1, 1);
413