xref: /freebsd/sys/dev/gpio/gpioths.c (revision 989da27e45020e15bc0d43f4a39533211834e472)
1662e30fcSMichael Zhilin /*-
25f0cf995SIan Lepore  * SPDX-License-Identifier: BSD-2-Clause
35f0cf995SIan Lepore  *
45f0cf995SIan Lepore  * Copyright (c) 2016 Michael Zhilin <mizhka@freebsd.org> All rights reserved.
5ffe0ca86SIan Lepore  * Copyright (c) 2019 Ian Lepore <ian@freebsd.org>
6662e30fcSMichael Zhilin  *
7662e30fcSMichael Zhilin  * Redistribution and use in source and binary forms, with or without
8662e30fcSMichael Zhilin  * modification, are permitted provided that the following conditions
9662e30fcSMichael Zhilin  * are met:
10662e30fcSMichael Zhilin  * 1. Redistributions of source code must retain the above copyright
11662e30fcSMichael Zhilin  *    notice, this list of conditions and the following disclaimer.
12662e30fcSMichael Zhilin  * 2. Redistributions in binary form must reproduce the above copyright
13662e30fcSMichael Zhilin  *    notice, this list of conditions and the following disclaimer in the
14662e30fcSMichael Zhilin  *    documentation and/or other materials provided with the distribution.
15662e30fcSMichael Zhilin  *
16662e30fcSMichael Zhilin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17662e30fcSMichael Zhilin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18662e30fcSMichael Zhilin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19662e30fcSMichael Zhilin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20662e30fcSMichael Zhilin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21662e30fcSMichael Zhilin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22662e30fcSMichael Zhilin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23662e30fcSMichael Zhilin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24662e30fcSMichael Zhilin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25662e30fcSMichael Zhilin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26662e30fcSMichael Zhilin  * SUCH DAMAGE.
27662e30fcSMichael Zhilin  */
28662e30fcSMichael Zhilin 
29662e30fcSMichael Zhilin /*
301398c4c5SIan Lepore  * GPIOTHS - Temp/Humidity sensor over GPIO.
311398c4c5SIan Lepore  *
32662e30fcSMichael Zhilin  * This is driver for Temperature & Humidity sensor which provides digital
33662e30fcSMichael Zhilin  * output over single-wire protocol from embedded 8-bit microcontroller.
345f0cf995SIan Lepore  * Note that it uses a custom single-wire protocol, it is not 1-wire(tm).
35662e30fcSMichael Zhilin  *
36ce508b36SIan Lepore  * This driver supports the following chips:
37ce508b36SIan Lepore  *   DHT11:  Temp   0c to 50c +-2.0c, Humidity 20% to  90% +-5%
38ce508b36SIan Lepore  *   DHT12:  Temp -20c to 60c +-0.5c, Humidity 20% to  95% +-5%
39ce508b36SIan Lepore  *   DHT21:  Temp -40c to 80c +-0.3c, Humidity  0% to 100% +-3%
40ce508b36SIan Lepore  *   DHT22:  Temp -40c to 80c +-0.3c, Humidity  0% to 100% +-2%
41ce508b36SIan Lepore  *   AM2301: Same as DHT21, but also supports i2c interface.
42ce508b36SIan Lepore  *   AM2302: Same as DHT22, but also supports i2c interface.
43ce508b36SIan Lepore  *
44662e30fcSMichael Zhilin  * Temp/Humidity sensor can't be discovered automatically, please specify hints
45662e30fcSMichael Zhilin  * as part of loader or kernel configuration:
46662e30fcSMichael Zhilin  *	hint.gpioths.0.at="gpiobus0"
47662e30fcSMichael Zhilin  *	hint.gpioths.0.pins=<PIN>
481398c4c5SIan Lepore  *
491398c4c5SIan Lepore  * Or configure via FDT data.
50662e30fcSMichael Zhilin  */
51662e30fcSMichael Zhilin 
521398c4c5SIan Lepore #include <sys/cdefs.h>
531398c4c5SIan Lepore __FBSDID("$FreeBSD$");
541398c4c5SIan Lepore 
551398c4c5SIan Lepore #include <sys/param.h>
561398c4c5SIan Lepore #include <sys/kernel.h>
571398c4c5SIan Lepore #include <sys/bus.h>
581398c4c5SIan Lepore #include <sys/gpio.h>
591398c4c5SIan Lepore #include <sys/module.h>
601398c4c5SIan Lepore #include <sys/errno.h>
611398c4c5SIan Lepore #include <sys/systm.h>
621398c4c5SIan Lepore #include <sys/sysctl.h>
63*989da27eSIan Lepore #include <sys/taskqueue.h>
641398c4c5SIan Lepore 
651398c4c5SIan Lepore #include <dev/gpio/gpiobusvar.h>
661398c4c5SIan Lepore 
671398c4c5SIan Lepore #ifdef FDT
681398c4c5SIan Lepore #include <dev/ofw/ofw_bus.h>
691398c4c5SIan Lepore #include <dev/ofw/ofw_bus_subr.h>
701398c4c5SIan Lepore 
711398c4c5SIan Lepore static struct ofw_compat_data compat_data[] = {
721398c4c5SIan Lepore 	{"dht11",  true},
731398c4c5SIan Lepore 	{NULL,     false}
741398c4c5SIan Lepore };
751398c4c5SIan Lepore OFWBUS_PNP_INFO(compat_data);
761398c4c5SIan Lepore SIMPLEBUS_PNP_INFO(compat_data);
771398c4c5SIan Lepore #endif /* FDT */
781398c4c5SIan Lepore 
791398c4c5SIan Lepore #define	PIN_IDX 0			/* Use the first/only configured pin. */
801398c4c5SIan Lepore 
81662e30fcSMichael Zhilin #define	GPIOTHS_POLLTIME	5	/* in seconds */
82662e30fcSMichael Zhilin 
83662e30fcSMichael Zhilin #define	GPIOTHS_DHT_STARTCYCLE	20000	/* 20ms = 20000us */
84662e30fcSMichael Zhilin #define	GPIOTHS_DHT_TIMEOUT	1000	/* 1ms = 1000us */
85662e30fcSMichael Zhilin #define	GPIOTHS_DHT_CYCLES	41
86662e30fcSMichael Zhilin #define	GPIOTHS_DHT_ONEBYTEMASK	0xFF
87662e30fcSMichael Zhilin 
88662e30fcSMichael Zhilin struct gpioths_softc {
89662e30fcSMichael Zhilin 	device_t		 dev;
901398c4c5SIan Lepore 	gpio_pin_t		 pin;
91662e30fcSMichael Zhilin 	int			 temp;
92662e30fcSMichael Zhilin 	int			 hum;
93662e30fcSMichael Zhilin 	int			 fails;
94*989da27eSIan Lepore 	struct timeout_task	 task;
95*989da27eSIan Lepore 	bool			 detaching;
96662e30fcSMichael Zhilin };
97662e30fcSMichael Zhilin 
98662e30fcSMichael Zhilin static int
99662e30fcSMichael Zhilin gpioths_probe(device_t dev)
100662e30fcSMichael Zhilin {
1011398c4c5SIan Lepore 	int rv;
1021398c4c5SIan Lepore 
1031398c4c5SIan Lepore 	/*
1041398c4c5SIan Lepore 	 * By default we only bid to attach if specifically added by our parent
1051398c4c5SIan Lepore 	 * (usually via hint.gpioths.#.at=busname).  On FDT systems we bid as
1061398c4c5SIan Lepore 	 * the default driver based on being configured in the FDT data.
1071398c4c5SIan Lepore 	 */
1081398c4c5SIan Lepore 	rv = BUS_PROBE_NOWILDCARD;
1091398c4c5SIan Lepore 
1101398c4c5SIan Lepore #ifdef FDT
1111398c4c5SIan Lepore 	if (ofw_bus_status_okay(dev) &&
1121398c4c5SIan Lepore 	    ofw_bus_search_compatible(dev, compat_data)->ocd_data)
1131398c4c5SIan Lepore 		rv = BUS_PROBE_DEFAULT;
1141398c4c5SIan Lepore #endif
1151398c4c5SIan Lepore 
1161398c4c5SIan Lepore 	device_set_desc(dev, "DHT11/DHT22 Temperature and Humidity Sensor");
1171398c4c5SIan Lepore 
1181398c4c5SIan Lepore 	return (rv);
119662e30fcSMichael Zhilin }
120662e30fcSMichael Zhilin 
121662e30fcSMichael Zhilin static int
1221398c4c5SIan Lepore gpioths_dht_timeuntil(struct gpioths_softc *sc, bool lev, uint32_t *time)
123662e30fcSMichael Zhilin {
1241398c4c5SIan Lepore 	bool		cur_level;
125662e30fcSMichael Zhilin 	int		i;
126662e30fcSMichael Zhilin 
127662e30fcSMichael Zhilin 	for (i = 0; i < GPIOTHS_DHT_TIMEOUT; i++) {
1281398c4c5SIan Lepore 		gpio_pin_is_active(sc->pin, &cur_level);
129662e30fcSMichael Zhilin 		if (cur_level == lev) {
130662e30fcSMichael Zhilin 			if (time != NULL)
131662e30fcSMichael Zhilin 				*time = i;
132662e30fcSMichael Zhilin 			return (0);
133662e30fcSMichael Zhilin 		}
134662e30fcSMichael Zhilin 		DELAY(1);
135662e30fcSMichael Zhilin 	}
136662e30fcSMichael Zhilin 
137662e30fcSMichael Zhilin 	/* Timeout */
138662e30fcSMichael Zhilin 	return (ETIMEDOUT);
139662e30fcSMichael Zhilin }
140662e30fcSMichael Zhilin 
1411398c4c5SIan Lepore static void
1421398c4c5SIan Lepore gpioths_dht_initread(struct gpioths_softc *sc)
143662e30fcSMichael Zhilin {
144662e30fcSMichael Zhilin 
145662e30fcSMichael Zhilin 	/*
1461398c4c5SIan Lepore 	 * According to specifications we need to drive the data line low for at
1471398c4c5SIan Lepore 	 * least 20ms then drive it high, to wake up the chip and signal it to
1481398c4c5SIan Lepore 	 * send a measurement. After sending this start signal, we switch the
1491398c4c5SIan Lepore 	 * pin back to input so the device can begin talking to us.
150662e30fcSMichael Zhilin 	 */
1511398c4c5SIan Lepore 	gpio_pin_setflags(sc->pin, GPIO_PIN_OUTPUT);
1521398c4c5SIan Lepore 	gpio_pin_set_active(sc->pin, false);
153*989da27eSIan Lepore 	pause_sbt("gpioths", ustosbt(GPIOTHS_DHT_STARTCYCLE), C_PREL(2), 0);
1541398c4c5SIan Lepore 	gpio_pin_set_active(sc->pin, true);
1551398c4c5SIan Lepore 	gpio_pin_setflags(sc->pin, GPIO_PIN_INPUT);
156662e30fcSMichael Zhilin }
157662e30fcSMichael Zhilin 
158662e30fcSMichael Zhilin static int
1591398c4c5SIan Lepore gpioths_dht_readbytes(struct gpioths_softc *sc)
160662e30fcSMichael Zhilin {
161662e30fcSMichael Zhilin 	uint32_t		 calibrations[GPIOTHS_DHT_CYCLES];
162662e30fcSMichael Zhilin 	uint32_t		 intervals[GPIOTHS_DHT_CYCLES];
163662e30fcSMichael Zhilin 	uint32_t		 err, avglen, value;
164662e30fcSMichael Zhilin 	uint8_t			 crc, calc;
165ce508b36SIan Lepore 	int			 i, negmul, offset, size, tmphi, tmplo;
166662e30fcSMichael Zhilin 
1671398c4c5SIan Lepore 	gpioths_dht_initread(sc);
168662e30fcSMichael Zhilin 
1691398c4c5SIan Lepore 	err = gpioths_dht_timeuntil(sc, false, NULL);
170662e30fcSMichael Zhilin 	if (err) {
1711398c4c5SIan Lepore 		device_printf(sc->dev, "err(START) = %d\n", err);
172662e30fcSMichael Zhilin 		goto error;
173662e30fcSMichael Zhilin 	}
174662e30fcSMichael Zhilin 
175662e30fcSMichael Zhilin 	/* reading - 41 cycles */
176662e30fcSMichael Zhilin 	for (i = 0; i < GPIOTHS_DHT_CYCLES; i++) {
1771398c4c5SIan Lepore 		err = gpioths_dht_timeuntil(sc, true, &calibrations[i]);
178662e30fcSMichael Zhilin 		if (err) {
1791398c4c5SIan Lepore 			device_printf(sc->dev, "err(CAL, %d) = %d\n", i, err);
180662e30fcSMichael Zhilin 			goto error;
181662e30fcSMichael Zhilin 		}
1821398c4c5SIan Lepore 		err = gpioths_dht_timeuntil(sc, false, &intervals[i]);
183662e30fcSMichael Zhilin 		if (err) {
1841398c4c5SIan Lepore 			device_printf(sc->dev, "err(INTERVAL, %d) = %d\n", i, err);
185662e30fcSMichael Zhilin 			goto error;
186662e30fcSMichael Zhilin 		}
187662e30fcSMichael Zhilin 	}
188662e30fcSMichael Zhilin 
189662e30fcSMichael Zhilin 	/* Calculate average data calibration cycle length */
190662e30fcSMichael Zhilin 	avglen = 0;
191662e30fcSMichael Zhilin 	for (i = 1; i < GPIOTHS_DHT_CYCLES; i++)
192662e30fcSMichael Zhilin 		avglen += calibrations[i];
193662e30fcSMichael Zhilin 
194662e30fcSMichael Zhilin 	avglen = avglen / (GPIOTHS_DHT_CYCLES - 1);
195662e30fcSMichael Zhilin 
196662e30fcSMichael Zhilin 	/* Calculate data */
197662e30fcSMichael Zhilin 	value = 0;
198662e30fcSMichael Zhilin 	offset = 1;
199662e30fcSMichael Zhilin 	size = sizeof(value) * 8;
200662e30fcSMichael Zhilin 	for (i = offset; i < size + offset; i++) {
201662e30fcSMichael Zhilin 		value <<= 1;
202662e30fcSMichael Zhilin 		if (intervals[i] > avglen)
203662e30fcSMichael Zhilin 			value += 1;
204662e30fcSMichael Zhilin 	}
205662e30fcSMichael Zhilin 
206662e30fcSMichael Zhilin 	/* Calculate CRC */
207662e30fcSMichael Zhilin 	crc = 0;
208662e30fcSMichael Zhilin 	offset = sizeof(value) * 8 + 1;
209662e30fcSMichael Zhilin 	size = sizeof(crc) * 8;
210662e30fcSMichael Zhilin 	for (i = offset;  i < size + offset; i++) {
211662e30fcSMichael Zhilin 		crc <<= 1;
212662e30fcSMichael Zhilin 		if (intervals[i] > avglen)
213662e30fcSMichael Zhilin 			crc += 1;
214662e30fcSMichael Zhilin 	}
215662e30fcSMichael Zhilin 
216662e30fcSMichael Zhilin 	calc = 0;
217662e30fcSMichael Zhilin 	for (i = 0; i < sizeof(value); i++)
218662e30fcSMichael Zhilin 		calc += (value >> (8*i)) & GPIOTHS_DHT_ONEBYTEMASK;
219662e30fcSMichael Zhilin 
220662e30fcSMichael Zhilin #ifdef GPIOTHS_DEBUG
221662e30fcSMichael Zhilin 	/* Debug bits */
222662e30fcSMichael Zhilin 	for (i = 0; i < GPIOTHS_DHT_CYCLES; i++)
223662e30fcSMichael Zhilin 		device_printf(dev, "%d: %d %d\n", i, calibrations[i],
224662e30fcSMichael Zhilin 		    intervals[i]);
225662e30fcSMichael Zhilin 
226662e30fcSMichael Zhilin 	device_printf(dev, "len=%d, data=%x, crc=%x/%x\n", avglen, value, crc,
227662e30fcSMichael Zhilin 	    calc);
228662e30fcSMichael Zhilin #endif /* GPIOTHS_DEBUG */
229662e30fcSMichael Zhilin 
230662e30fcSMichael Zhilin 	/* CRC check */
231662e30fcSMichael Zhilin 	if (calc != crc) {
232662e30fcSMichael Zhilin 		err = -1;
233662e30fcSMichael Zhilin 		goto error;
234662e30fcSMichael Zhilin 	}
235662e30fcSMichael Zhilin 
236ce508b36SIan Lepore 	/*
237ce508b36SIan Lepore 	 * For DHT11/12, the values are split into 8 bits of integer and 8 bits
238ce508b36SIan Lepore 	 * of fractional tenths.  On DHT11 the fraction bytes are always zero.
239ce508b36SIan Lepore 	 * On DHT12 the sign bit is in the high bit of the fraction byte.
240ce508b36SIan Lepore 	 *  - DHT11: 0HHHHHHH 00000000 00TTTTTT 00000000
241ce508b36SIan Lepore 	 *  - DHT12: 0HHHHHHH 0000hhhh 00TTTTTT s000tttt
242ce508b36SIan Lepore 	 *
243ce508b36SIan Lepore 	 * For DHT21/21, the values are are encoded in 16 bits each, with the
244ce508b36SIan Lepore 	 * temperature sign bit in the high bit.  The values are tenths of a
245ce508b36SIan Lepore 	 * degree C and tenths of a percent RH.
246ce508b36SIan Lepore 	 *  - DHT21: 000000HH HHHHHHHH s00000TT TTTTTTTT
247ce508b36SIan Lepore 	 *  - DHT22: 000000HH HHHHHHHH s00000TT TTTTTTTT
248ce508b36SIan Lepore 	 *
249ce508b36SIan Lepore 	 * For all devices, some bits are always zero because of the range of
250ce508b36SIan Lepore 	 * values supported by the device.
251ce508b36SIan Lepore 	 *
252ce508b36SIan Lepore 	 * We figure out how to decode things based on the high byte of the
253ce508b36SIan Lepore 	 * humidity.  A DHT21/22 cannot report a value greater than 3 in
254ce508b36SIan Lepore 	 * the upper bits of its 16-bit humidity.  A DHT11/12 should not report
255ce508b36SIan Lepore 	 * a value lower than 20.  To allow for the possibility that a device
256ce508b36SIan Lepore 	 * could report a value slightly out of its sensitivity range, we split
2571398c4c5SIan Lepore 	 * the difference and say if the value is greater than 10 it must be a
2581398c4c5SIan Lepore 	 * DHT11/12 (that would be a humidity over 256% on a DHT21/22).
259ce508b36SIan Lepore 	 */
260ce508b36SIan Lepore #define	DK_OFFSET 2731 /* Offset between K and C, in decikelvins. */
261ce508b36SIan Lepore 	if ((value >> 24) > 10) {
262ce508b36SIan Lepore 		/* DHT11 or DHT12 */
263ce508b36SIan Lepore 		tmphi = (value >> 8) & 0x3f;
264ce508b36SIan Lepore 		tmplo = value & 0x0f;
265ce508b36SIan Lepore 		negmul = (value & 0x80) ? -1 : 1;
266ce508b36SIan Lepore 		sc->temp = DK_OFFSET + (negmul * (tmphi * 10 + tmplo));
267ce508b36SIan Lepore 		sc->hum = (value >> 24) & 0x7f;
268ce508b36SIan Lepore 	} else {
269ce508b36SIan Lepore                 /* DHT21 or DHT22 */
270ce508b36SIan Lepore 		negmul = (value & 0x8000) ? -1 : 1;
271ce508b36SIan Lepore 		sc->temp = DK_OFFSET + (negmul * (value & 0x03ff));
272ce508b36SIan Lepore 		sc->hum = ((value >> 16) & 0x03ff) / 10;
273ce508b36SIan Lepore 	}
274ce508b36SIan Lepore 
275662e30fcSMichael Zhilin 	sc->fails = 0;
276662e30fcSMichael Zhilin 
277662e30fcSMichael Zhilin #ifdef GPIOTHS_DEBUG
278662e30fcSMichael Zhilin 	/* Debug bits */
279662e30fcSMichael Zhilin 	device_printf(dev, "fails=%d, temp=%d, hum=%d\n", sc->fails,
280662e30fcSMichael Zhilin 	    sc->temp, sc->hum);
281662e30fcSMichael Zhilin #endif /* GPIOTHS_DEBUG */
282662e30fcSMichael Zhilin 
283662e30fcSMichael Zhilin 	return (0);
284662e30fcSMichael Zhilin error:
285662e30fcSMichael Zhilin 	sc->fails++;
286662e30fcSMichael Zhilin 	return (err);
287662e30fcSMichael Zhilin }
288662e30fcSMichael Zhilin 
289662e30fcSMichael Zhilin static void
290*989da27eSIan Lepore gpioths_poll(void *arg, int pending __unused)
291662e30fcSMichael Zhilin {
292662e30fcSMichael Zhilin 	struct gpioths_softc	*sc;
293662e30fcSMichael Zhilin 
2941398c4c5SIan Lepore 	sc = (struct gpioths_softc *)arg;
295662e30fcSMichael Zhilin 
2961398c4c5SIan Lepore 	gpioths_dht_readbytes(sc);
297*989da27eSIan Lepore 	if (!sc->detaching)
298*989da27eSIan Lepore 		taskqueue_enqueue_timeout_sbt(taskqueue_thread, &sc->task,
299*989da27eSIan Lepore 		    GPIOTHS_POLLTIME * SBT_1S, 0, C_PREL(3));
300662e30fcSMichael Zhilin }
301662e30fcSMichael Zhilin 
302662e30fcSMichael Zhilin static int
303662e30fcSMichael Zhilin gpioths_attach(device_t dev)
304662e30fcSMichael Zhilin {
305662e30fcSMichael Zhilin 	struct gpioths_softc	*sc;
306662e30fcSMichael Zhilin 	struct sysctl_ctx_list	*ctx;
307662e30fcSMichael Zhilin 	struct sysctl_oid	*tree;
3081398c4c5SIan Lepore 	int err;
309662e30fcSMichael Zhilin 
310662e30fcSMichael Zhilin 	sc = device_get_softc(dev);
311662e30fcSMichael Zhilin 	ctx = device_get_sysctl_ctx(dev);
312662e30fcSMichael Zhilin 	tree = device_get_sysctl_tree(dev);
313662e30fcSMichael Zhilin 
314662e30fcSMichael Zhilin 	sc->dev = dev;
315662e30fcSMichael Zhilin 
316*989da27eSIan Lepore 	TIMEOUT_TASK_INIT(taskqueue_thread, &sc->task, 0, gpioths_poll, sc);
317*989da27eSIan Lepore 
3181398c4c5SIan Lepore #ifdef FDT
3191398c4c5SIan Lepore 	/* Try to configure our pin from fdt data on fdt-based systems. */
3201398c4c5SIan Lepore 	err = gpio_pin_get_by_ofw_idx(dev, ofw_bus_get_node(dev), PIN_IDX,
3211398c4c5SIan Lepore 	    &sc->pin);
3221398c4c5SIan Lepore #else
3231398c4c5SIan Lepore 	err = ENOENT;
3241398c4c5SIan Lepore #endif
3251398c4c5SIan Lepore 	/*
3261398c4c5SIan Lepore 	 * If we didn't get configured by fdt data and our parent is gpiobus,
3271398c4c5SIan Lepore 	 * see if we can be configured by the bus (allows hinted attachment even
3281398c4c5SIan Lepore 	 * on fdt-based systems).
3291398c4c5SIan Lepore 	 */
3301398c4c5SIan Lepore 	if (err != 0 &&
3311398c4c5SIan Lepore 	    strcmp("gpiobus", device_get_name(device_get_parent(dev))) == 0)
3321398c4c5SIan Lepore 		err = gpio_pin_get_by_child_index(dev, PIN_IDX, &sc->pin);
3331398c4c5SIan Lepore 
3341398c4c5SIan Lepore 	/* If we didn't get configured by either method, whine and punt. */
3351398c4c5SIan Lepore 	if (err != 0) {
3361398c4c5SIan Lepore 		device_printf(sc->dev,
3371398c4c5SIan Lepore 		    "cannot acquire gpio pin (config error)\n");
3381398c4c5SIan Lepore 		return (err);
3391398c4c5SIan Lepore 	}
3401398c4c5SIan Lepore 
3411398c4c5SIan Lepore 	/*
3421398c4c5SIan Lepore 	 * Ensure we have control of our pin, and preset the data line to its
3431398c4c5SIan Lepore 	 * idle condition (high).  Leave the line in input mode, relying on the
3441398c4c5SIan Lepore 	 * external pullup to keep the line high while idle.
3451398c4c5SIan Lepore 	 */
3461398c4c5SIan Lepore 	err = gpio_pin_setflags(sc->pin, GPIO_PIN_OUTPUT);
3471398c4c5SIan Lepore 	if (err != 0) {
3481398c4c5SIan Lepore 		device_printf(dev, "gpio_pin_setflags(OUT) = %d\n", err);
3491398c4c5SIan Lepore 		return (err);
3501398c4c5SIan Lepore 	}
3511398c4c5SIan Lepore 	err = gpio_pin_set_active(sc->pin, true);
3521398c4c5SIan Lepore 	if (err != 0) {
3531398c4c5SIan Lepore 		device_printf(dev, "gpio_pin_set_active(false) = %d\n", err);
3541398c4c5SIan Lepore 		return (err);
3551398c4c5SIan Lepore 	}
3561398c4c5SIan Lepore 	err = gpio_pin_setflags(sc->pin, GPIO_PIN_INPUT);
3571398c4c5SIan Lepore 	if (err != 0) {
3581398c4c5SIan Lepore 		device_printf(dev, "gpio_pin_setflags(IN) = %d\n", err);
3591398c4c5SIan Lepore 		return (err);
3601398c4c5SIan Lepore 	}
3611398c4c5SIan Lepore 
3629f8df20cSIan Lepore 	/*
3639f8df20cSIan Lepore 	 * Do an initial read so we have correct values for reporting before
364*989da27eSIan Lepore 	 * registering the sysctls that can access those values.  This also
365*989da27eSIan Lepore 	 * schedules the periodic polling the driver does every few seconds to
366*989da27eSIan Lepore 	 * update the sysctl variables.
3679f8df20cSIan Lepore 	 */
368*989da27eSIan Lepore 	gpioths_poll(sc, 0);
369662e30fcSMichael Zhilin 
37078e70ab9SIan Lepore 	sysctl_add_oid(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "temperature",				\
37178e70ab9SIan Lepore 	    CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE,
372ce508b36SIan Lepore 	    &sc->temp, 0, sysctl_handle_int, "IK", "temperature", NULL);
373662e30fcSMichael Zhilin 
37478e70ab9SIan Lepore 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "humidity",
37578e70ab9SIan Lepore 	    CTLFLAG_RD, &sc->hum, 0, "relative humidity(%)");
376662e30fcSMichael Zhilin 
37778e70ab9SIan Lepore 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "fails",
37878e70ab9SIan Lepore 	    CTLFLAG_RD, &sc->fails, 0,
37978e70ab9SIan Lepore 	    "failures since last successful read");
380662e30fcSMichael Zhilin 
381662e30fcSMichael Zhilin 	return (0);
382662e30fcSMichael Zhilin }
383662e30fcSMichael Zhilin 
384662e30fcSMichael Zhilin static int
385662e30fcSMichael Zhilin gpioths_detach(device_t dev)
386662e30fcSMichael Zhilin {
3879f8df20cSIan Lepore 	struct gpioths_softc	*sc;
3889f8df20cSIan Lepore 
3899f8df20cSIan Lepore 	sc = device_get_softc(dev);
3901398c4c5SIan Lepore 	gpio_pin_release(sc->pin);
391*989da27eSIan Lepore 	sc->detaching = true;
392*989da27eSIan Lepore 	while (taskqueue_cancel_timeout(taskqueue_thread, &sc->task, NULL) != 0)
393*989da27eSIan Lepore 		taskqueue_drain_timeout(taskqueue_thread, &sc->task);
394662e30fcSMichael Zhilin 
395662e30fcSMichael Zhilin 	return (0);
396662e30fcSMichael Zhilin }
397662e30fcSMichael Zhilin 
398662e30fcSMichael Zhilin /* Driver bits */
399662e30fcSMichael Zhilin static device_method_t gpioths_methods[] = {
400662e30fcSMichael Zhilin 	/* Device interface */
401662e30fcSMichael Zhilin 	DEVMETHOD(device_probe,			gpioths_probe),
402662e30fcSMichael Zhilin 	DEVMETHOD(device_attach,		gpioths_attach),
403662e30fcSMichael Zhilin 	DEVMETHOD(device_detach,		gpioths_detach),
404662e30fcSMichael Zhilin 
405662e30fcSMichael Zhilin 	DEVMETHOD_END
406662e30fcSMichael Zhilin };
407662e30fcSMichael Zhilin 
40835e9bfc9SIan Lepore static devclass_t gpioths_devclass;
40935e9bfc9SIan Lepore 
410662e30fcSMichael Zhilin DEFINE_CLASS_0(gpioths, gpioths_driver, gpioths_methods, sizeof(struct gpioths_softc));
4111398c4c5SIan Lepore 
4121398c4c5SIan Lepore #ifdef FDT
4131398c4c5SIan Lepore DRIVER_MODULE(gpioths, simplebus, gpioths_driver, gpioths_devclass, 0, 0);
4141398c4c5SIan Lepore #endif
4151398c4c5SIan Lepore 
416662e30fcSMichael Zhilin DRIVER_MODULE(gpioths, gpiobus, gpioths_driver, gpioths_devclass, 0, 0);
41735e9bfc9SIan Lepore MODULE_DEPEND(gpioths, gpiobus, 1, 1, 1);
418