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