xref: /freebsd/sys/dev/gpio/gpioths.c (revision ce508b364cea1ad6860a3cfcf0ad4f8d70ea7f16)
1662e30fcSMichael Zhilin /*-
2662e30fcSMichael Zhilin  * Copyright (c) 2016 Michael Zhilin <mizhka@freebsd.org>
3662e30fcSMichael Zhilin  * All rights reserved.
4662e30fcSMichael Zhilin  *
5662e30fcSMichael Zhilin  * Redistribution and use in source and binary forms, with or without
6662e30fcSMichael Zhilin  * modification, are permitted provided that the following conditions
7662e30fcSMichael Zhilin  * are met:
8662e30fcSMichael Zhilin  * 1. Redistributions of source code must retain the above copyright
9662e30fcSMichael Zhilin  *    notice, this list of conditions and the following disclaimer.
10662e30fcSMichael Zhilin  * 2. Redistributions in binary form must reproduce the above copyright
11662e30fcSMichael Zhilin  *    notice, this list of conditions and the following disclaimer in the
12662e30fcSMichael Zhilin  *    documentation and/or other materials provided with the distribution.
13662e30fcSMichael Zhilin  *
14662e30fcSMichael Zhilin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15662e30fcSMichael Zhilin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16662e30fcSMichael Zhilin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17662e30fcSMichael Zhilin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18662e30fcSMichael Zhilin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19662e30fcSMichael Zhilin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20662e30fcSMichael Zhilin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21662e30fcSMichael Zhilin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22662e30fcSMichael Zhilin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23662e30fcSMichael Zhilin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24662e30fcSMichael Zhilin  * SUCH DAMAGE.
25662e30fcSMichael Zhilin  */
26662e30fcSMichael Zhilin 
27662e30fcSMichael Zhilin #include <sys/cdefs.h>
28662e30fcSMichael Zhilin __FBSDID("$FreeBSD$");
29662e30fcSMichael Zhilin 
30662e30fcSMichael Zhilin #include <sys/param.h>
31662e30fcSMichael Zhilin #include <sys/kernel.h>
32662e30fcSMichael Zhilin #include <sys/bus.h>
33662e30fcSMichael Zhilin #include <sys/module.h>
34662e30fcSMichael Zhilin #include <sys/errno.h>
35662e30fcSMichael Zhilin #include <sys/systm.h>
36662e30fcSMichael Zhilin #include <sys/sysctl.h>
37662e30fcSMichael Zhilin 
38662e30fcSMichael Zhilin #include <machine/bus.h>
39662e30fcSMichael Zhilin #include <sys/rman.h>
40662e30fcSMichael Zhilin #include <sys/gpio.h>
41662e30fcSMichael Zhilin #include <machine/resource.h>
42662e30fcSMichael Zhilin 
43662e30fcSMichael Zhilin #include "gpiobus_if.h"
44662e30fcSMichael Zhilin 
45662e30fcSMichael Zhilin /*
46662e30fcSMichael Zhilin  * GPIOTHS - Temp/Humidity sensor over GPIO, e.g. DHT11/DHT22
47662e30fcSMichael Zhilin  * This is driver for Temperature & Humidity sensor which provides digital
48662e30fcSMichael Zhilin  * output over single-wire protocol from embedded 8-bit microcontroller.
49662e30fcSMichael Zhilin  *
50*ce508b36SIan Lepore  * This driver supports the following chips:
51*ce508b36SIan Lepore  *   DHT11:  Temp   0c to 50c +-2.0c, Humidity 20% to  90% +-5%
52*ce508b36SIan Lepore  *   DHT12:  Temp -20c to 60c +-0.5c, Humidity 20% to  95% +-5%
53*ce508b36SIan Lepore  *   DHT21:  Temp -40c to 80c +-0.3c, Humidity  0% to 100% +-3%
54*ce508b36SIan Lepore  *   DHT22:  Temp -40c to 80c +-0.3c, Humidity  0% to 100% +-2%
55*ce508b36SIan Lepore  *   AM2301: Same as DHT21, but also supports i2c interface.
56*ce508b36SIan Lepore  *   AM2302: Same as DHT22, but also supports i2c interface.
57*ce508b36SIan Lepore  *
58662e30fcSMichael Zhilin  * Temp/Humidity sensor can't be discovered automatically, please specify hints
59662e30fcSMichael Zhilin  * as part of loader or kernel configuration:
60662e30fcSMichael Zhilin  *	hint.gpioths.0.at="gpiobus0"
61662e30fcSMichael Zhilin  *	hint.gpioths.0.pins=<PIN>
62662e30fcSMichael Zhilin  */
63662e30fcSMichael Zhilin 
64662e30fcSMichael Zhilin #define	GPIOTHS_POLLTIME	5	/* in seconds */
65662e30fcSMichael Zhilin 
66662e30fcSMichael Zhilin #define	GPIOTHS_DHT_STARTCYCLE	20000	/* 20ms = 20000us */
67662e30fcSMichael Zhilin #define	GPIOTHS_DHT_TIMEOUT	1000	/* 1ms = 1000us */
68662e30fcSMichael Zhilin #define	GPIOTHS_DHT_CYCLES	41
69662e30fcSMichael Zhilin #define	GPIOTHS_DHT_ONEBYTEMASK	0xFF
70662e30fcSMichael Zhilin 
71662e30fcSMichael Zhilin struct gpioths_softc {
72662e30fcSMichael Zhilin 	device_t		 dev;
73662e30fcSMichael Zhilin 	int			 temp;
74662e30fcSMichael Zhilin 	int			 hum;
75662e30fcSMichael Zhilin 	int			 fails;
76662e30fcSMichael Zhilin 	struct callout		 callout;
77662e30fcSMichael Zhilin };
78662e30fcSMichael Zhilin 
79662e30fcSMichael Zhilin static devclass_t gpioths_devclass;
80662e30fcSMichael Zhilin 
81662e30fcSMichael Zhilin /* Prototypes */
82662e30fcSMichael Zhilin static int		gpioths_probe(device_t dev);
83662e30fcSMichael Zhilin static int		gpioths_attach(device_t dev);
84662e30fcSMichael Zhilin static int		gpioths_detach(device_t dev);
85662e30fcSMichael Zhilin static void		gpioths_poll(void *arg);
86662e30fcSMichael Zhilin 
87662e30fcSMichael Zhilin /* DHT-specific methods */
88662e30fcSMichael Zhilin static int		gpioths_dht_initread(device_t bus, device_t dev);
89662e30fcSMichael Zhilin static int		gpioths_dht_readbytes(device_t bus, device_t dev);
90662e30fcSMichael Zhilin static int		gpioths_dht_timeuntil(device_t bus, device_t dev,
91662e30fcSMichael Zhilin 			    uint32_t lev, uint32_t *time);
92662e30fcSMichael Zhilin 
93662e30fcSMichael Zhilin /* Implementation */
94662e30fcSMichael Zhilin static int
95662e30fcSMichael Zhilin gpioths_probe(device_t dev)
96662e30fcSMichael Zhilin {
97662e30fcSMichael Zhilin 	device_set_desc(dev, "Temperature and Humidity Sensor over GPIO");
98662e30fcSMichael Zhilin 	return (0);
99662e30fcSMichael Zhilin }
100662e30fcSMichael Zhilin 
101662e30fcSMichael Zhilin static int
102662e30fcSMichael Zhilin gpioths_dht_timeuntil(device_t bus, device_t dev, uint32_t lev, uint32_t *time)
103662e30fcSMichael Zhilin {
104662e30fcSMichael Zhilin 	uint32_t	cur_level;
105662e30fcSMichael Zhilin 	int		i;
106662e30fcSMichael Zhilin 
107662e30fcSMichael Zhilin 	for (i = 0; i < GPIOTHS_DHT_TIMEOUT; i++) {
108662e30fcSMichael Zhilin 		GPIOBUS_PIN_GET(bus, dev, 0, &cur_level);
109662e30fcSMichael Zhilin 		if (cur_level == lev) {
110662e30fcSMichael Zhilin 			if (time != NULL)
111662e30fcSMichael Zhilin 				*time = i;
112662e30fcSMichael Zhilin 			return (0);
113662e30fcSMichael Zhilin 		}
114662e30fcSMichael Zhilin 		DELAY(1);
115662e30fcSMichael Zhilin 	}
116662e30fcSMichael Zhilin 
117662e30fcSMichael Zhilin 	/* Timeout */
118662e30fcSMichael Zhilin 	return (ETIMEDOUT);
119662e30fcSMichael Zhilin }
120662e30fcSMichael Zhilin 
121662e30fcSMichael Zhilin static int
122662e30fcSMichael Zhilin gpioths_dht_initread(device_t bus, device_t dev)
123662e30fcSMichael Zhilin {
124662e30fcSMichael Zhilin 	int	err;
125662e30fcSMichael Zhilin 
126662e30fcSMichael Zhilin 	err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_OUTPUT);
127662e30fcSMichael Zhilin 	if (err != 0) {
128662e30fcSMichael Zhilin 		device_printf(dev, "err(GPIOBUS_PIN_SETFLAGS, OUT) = %d\n", err);
129662e30fcSMichael Zhilin 		return (err);
130662e30fcSMichael Zhilin 	}
131662e30fcSMichael Zhilin 	DELAY(1);
132662e30fcSMichael Zhilin 
133662e30fcSMichael Zhilin 	err = GPIOBUS_PIN_SET(bus, dev, 0, GPIO_PIN_LOW);
134662e30fcSMichael Zhilin 	if (err != 0) {
135662e30fcSMichael Zhilin 		device_printf(dev, "err(GPIOBUS_PIN_SET, LOW) = %d\n", err);
136662e30fcSMichael Zhilin 		return (err);
137662e30fcSMichael Zhilin 	}
138662e30fcSMichael Zhilin 
139662e30fcSMichael Zhilin 	/*
140662e30fcSMichael Zhilin 	 * According to specifications we need to wait no more than 18ms
141662e30fcSMichael Zhilin 	 * to start data transfer
142662e30fcSMichael Zhilin 	 */
143662e30fcSMichael Zhilin 	DELAY(GPIOTHS_DHT_STARTCYCLE);
144662e30fcSMichael Zhilin 	err = GPIOBUS_PIN_SET(bus, dev, 0, GPIO_PIN_HIGH);
145662e30fcSMichael Zhilin 	if (err != 0) {
146662e30fcSMichael Zhilin 		device_printf(dev, "err(GPIOBUS_PIN_SET, HIGH) = %d\n", err);
147662e30fcSMichael Zhilin 		return (err);
148662e30fcSMichael Zhilin 	}
149662e30fcSMichael Zhilin 
150662e30fcSMichael Zhilin 	DELAY(1);
151662e30fcSMichael Zhilin 	err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_INPUT) ;
152662e30fcSMichael Zhilin 	if (err != 0) {
153662e30fcSMichael Zhilin 		device_printf(dev, "err(GPIOBUS_PIN_SETFLAGS, IN) = %d\n", err);
154662e30fcSMichael Zhilin 		return (err);
155662e30fcSMichael Zhilin 	}
156662e30fcSMichael Zhilin 
157662e30fcSMichael Zhilin 	DELAY(1);
158662e30fcSMichael Zhilin 	return (0);
159662e30fcSMichael Zhilin }
160662e30fcSMichael Zhilin 
161662e30fcSMichael Zhilin static int
162662e30fcSMichael Zhilin gpioths_dht_readbytes(device_t bus, device_t dev)
163662e30fcSMichael Zhilin {
164662e30fcSMichael Zhilin 	struct gpioths_softc	*sc;
165662e30fcSMichael Zhilin 	uint32_t		 calibrations[GPIOTHS_DHT_CYCLES];
166662e30fcSMichael Zhilin 	uint32_t		 intervals[GPIOTHS_DHT_CYCLES];
167662e30fcSMichael Zhilin 	uint32_t		 err, avglen, value;
168662e30fcSMichael Zhilin 	uint8_t			 crc, calc;
169*ce508b36SIan Lepore 	int			 i, negmul, offset, size, tmphi, tmplo;
170662e30fcSMichael Zhilin 
171662e30fcSMichael Zhilin 	sc = device_get_softc(dev);
172662e30fcSMichael Zhilin 
173662e30fcSMichael Zhilin 	err = gpioths_dht_initread(bus,dev);
174662e30fcSMichael Zhilin 	if (err) {
175662e30fcSMichael Zhilin 		device_printf(dev, "gpioths_dht_initread error = %d\n", err);
176662e30fcSMichael Zhilin 		goto error;
177662e30fcSMichael Zhilin 	}
178662e30fcSMichael Zhilin 
179662e30fcSMichael Zhilin 	err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_LOW, NULL);
180662e30fcSMichael Zhilin 	if (err) {
181662e30fcSMichael Zhilin 		device_printf(dev, "err(START) = %d\n", err);
182662e30fcSMichael Zhilin 		goto error;
183662e30fcSMichael Zhilin 	}
184662e30fcSMichael Zhilin 
185662e30fcSMichael Zhilin 	/* reading - 41 cycles */
186662e30fcSMichael Zhilin 	for (i = 0; i < GPIOTHS_DHT_CYCLES; i++) {
187662e30fcSMichael Zhilin 		err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_HIGH,
188662e30fcSMichael Zhilin 		          &calibrations[i]);
189662e30fcSMichael Zhilin 		if (err) {
190662e30fcSMichael Zhilin 			device_printf(dev, "err(CAL, %d) = %d\n", i, err);
191662e30fcSMichael Zhilin 			goto error;
192662e30fcSMichael Zhilin 		}
193662e30fcSMichael Zhilin 		err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_LOW,
194662e30fcSMichael Zhilin 			  &intervals[i]);
195662e30fcSMichael Zhilin 		if (err) {
196662e30fcSMichael Zhilin 			device_printf(dev, "err(INTERVAL, %d) = %d\n", i, err);
197662e30fcSMichael Zhilin 			goto error;
198662e30fcSMichael Zhilin 		}
199662e30fcSMichael Zhilin 	}
200662e30fcSMichael Zhilin 
2019f8df20cSIan Lepore 	err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_INPUT);
202662e30fcSMichael Zhilin 	if (err != 0) {
2039f8df20cSIan Lepore 		device_printf(dev, "err(FINAL_SETFLAGS, IN) = %d\n", err);
204662e30fcSMichael Zhilin 		goto error;
205662e30fcSMichael Zhilin 	}
206662e30fcSMichael Zhilin 	DELAY(1);
207662e30fcSMichael Zhilin 
208662e30fcSMichael Zhilin 	/* Calculate average data calibration cycle length */
209662e30fcSMichael Zhilin 	avglen = 0;
210662e30fcSMichael Zhilin 	for (i = 1; i < GPIOTHS_DHT_CYCLES; i++)
211662e30fcSMichael Zhilin 		avglen += calibrations[i];
212662e30fcSMichael Zhilin 
213662e30fcSMichael Zhilin 	avglen = avglen / (GPIOTHS_DHT_CYCLES - 1);
214662e30fcSMichael Zhilin 
215662e30fcSMichael Zhilin 	/* Calculate data */
216662e30fcSMichael Zhilin 	value = 0;
217662e30fcSMichael Zhilin 	offset = 1;
218662e30fcSMichael Zhilin 	size = sizeof(value) * 8;
219662e30fcSMichael Zhilin 	for (i = offset; i < size + offset; i++) {
220662e30fcSMichael Zhilin 		value <<= 1;
221662e30fcSMichael Zhilin 		if (intervals[i] > avglen)
222662e30fcSMichael Zhilin 			value += 1;
223662e30fcSMichael Zhilin 	}
224662e30fcSMichael Zhilin 
225662e30fcSMichael Zhilin 	/* Calculate CRC */
226662e30fcSMichael Zhilin 	crc = 0;
227662e30fcSMichael Zhilin 	offset = sizeof(value) * 8 + 1;
228662e30fcSMichael Zhilin 	size = sizeof(crc) * 8;
229662e30fcSMichael Zhilin 	for (i = offset;  i < size + offset; i++) {
230662e30fcSMichael Zhilin 		crc <<= 1;
231662e30fcSMichael Zhilin 		if (intervals[i] > avglen)
232662e30fcSMichael Zhilin 			crc += 1;
233662e30fcSMichael Zhilin 	}
234662e30fcSMichael Zhilin 
235662e30fcSMichael Zhilin 	calc = 0;
236662e30fcSMichael Zhilin 	for (i = 0; i < sizeof(value); i++)
237662e30fcSMichael Zhilin 		calc += (value >> (8*i)) & GPIOTHS_DHT_ONEBYTEMASK;
238662e30fcSMichael Zhilin 
239662e30fcSMichael Zhilin #ifdef GPIOTHS_DEBUG
240662e30fcSMichael Zhilin 	/* Debug bits */
241662e30fcSMichael Zhilin 	for (i = 0; i < GPIOTHS_DHT_CYCLES; i++)
242662e30fcSMichael Zhilin 		device_printf(dev, "%d: %d %d\n", i, calibrations[i],
243662e30fcSMichael Zhilin 		    intervals[i]);
244662e30fcSMichael Zhilin 
245662e30fcSMichael Zhilin 	device_printf(dev, "len=%d, data=%x, crc=%x/%x\n", avglen, value, crc,
246662e30fcSMichael Zhilin 	    calc);
247662e30fcSMichael Zhilin #endif /* GPIOTHS_DEBUG */
248662e30fcSMichael Zhilin 
249662e30fcSMichael Zhilin 	/* CRC check */
250662e30fcSMichael Zhilin 	if (calc != crc) {
251662e30fcSMichael Zhilin 		err = -1;
252662e30fcSMichael Zhilin 		goto error;
253662e30fcSMichael Zhilin 	}
254662e30fcSMichael Zhilin 
255*ce508b36SIan Lepore 	/*
256*ce508b36SIan Lepore 	 * For DHT11/12, the values are split into 8 bits of integer and 8 bits
257*ce508b36SIan Lepore 	 * of fractional tenths.  On DHT11 the fraction bytes are always zero.
258*ce508b36SIan Lepore 	 * On DHT12 the sign bit is in the high bit of the fraction byte.
259*ce508b36SIan Lepore 	 *  - DHT11: 0HHHHHHH 00000000 00TTTTTT 00000000
260*ce508b36SIan Lepore 	 *  - DHT12: 0HHHHHHH 0000hhhh 00TTTTTT s000tttt
261*ce508b36SIan Lepore 	 *
262*ce508b36SIan Lepore 	 * For DHT21/21, the values are are encoded in 16 bits each, with the
263*ce508b36SIan Lepore 	 * temperature sign bit in the high bit.  The values are tenths of a
264*ce508b36SIan Lepore 	 * degree C and tenths of a percent RH.
265*ce508b36SIan Lepore 	 *  - DHT21: 000000HH HHHHHHHH s00000TT TTTTTTTT
266*ce508b36SIan Lepore 	 *  - DHT22: 000000HH HHHHHHHH s00000TT TTTTTTTT
267*ce508b36SIan Lepore 	 *
268*ce508b36SIan Lepore 	 * For all devices, some bits are always zero because of the range of
269*ce508b36SIan Lepore 	 * values supported by the device.
270*ce508b36SIan Lepore 	 *
271*ce508b36SIan Lepore 	 * We figure out how to decode things based on the high byte of the
272*ce508b36SIan Lepore 	 * humidity.  A DHT21/22 cannot report a value greater than 3 in
273*ce508b36SIan Lepore 	 * the upper bits of its 16-bit humidity.  A DHT11/12 should not report
274*ce508b36SIan Lepore 	 * a value lower than 20.  To allow for the possibility that a device
275*ce508b36SIan Lepore 	 * could report a value slightly out of its sensitivity range, we split
276*ce508b36SIan Lepore 	 * the difference and say if the value is greater than 10 it cannot be a
277*ce508b36SIan Lepore 	 * DHT22 (that would be a humidity over 256%).
278*ce508b36SIan Lepore 	 */
279*ce508b36SIan Lepore #define	DK_OFFSET 2731 /* Offset between K and C, in decikelvins. */
280*ce508b36SIan Lepore 	if ((value >> 24) > 10) {
281*ce508b36SIan Lepore 		/* DHT11 or DHT12 */
282*ce508b36SIan Lepore 		tmphi = (value >> 8) & 0x3f;
283*ce508b36SIan Lepore 		tmplo = value & 0x0f;
284*ce508b36SIan Lepore 		negmul = (value & 0x80) ? -1 : 1;
285*ce508b36SIan Lepore 		sc->temp = DK_OFFSET + (negmul * (tmphi * 10 + tmplo));
286*ce508b36SIan Lepore 		sc->hum = (value >> 24) & 0x7f;
287*ce508b36SIan Lepore 	} else {
288*ce508b36SIan Lepore                 /* DHT21 or DHT22 */
289*ce508b36SIan Lepore 		negmul = (value & 0x8000) ? -1 : 1;
290*ce508b36SIan Lepore 		sc->temp = DK_OFFSET + (negmul * (value & 0x03ff));
291*ce508b36SIan Lepore 		sc->hum = ((value >> 16) & 0x03ff) / 10;
292*ce508b36SIan Lepore 	}
293*ce508b36SIan Lepore 
294662e30fcSMichael Zhilin 	sc->fails = 0;
295662e30fcSMichael Zhilin 
296662e30fcSMichael Zhilin #ifdef GPIOTHS_DEBUG
297662e30fcSMichael Zhilin 	/* Debug bits */
298662e30fcSMichael Zhilin 	device_printf(dev, "fails=%d, temp=%d, hum=%d\n", sc->fails,
299662e30fcSMichael Zhilin 	    sc->temp, sc->hum);
300662e30fcSMichael Zhilin #endif /* GPIOTHS_DEBUG */
301662e30fcSMichael Zhilin 
302662e30fcSMichael Zhilin 	return (0);
303662e30fcSMichael Zhilin error:
304662e30fcSMichael Zhilin 	sc->fails++;
305662e30fcSMichael Zhilin 	return (err);
306662e30fcSMichael Zhilin }
307662e30fcSMichael Zhilin 
308662e30fcSMichael Zhilin static void
309662e30fcSMichael Zhilin gpioths_poll(void *arg)
310662e30fcSMichael Zhilin {
311662e30fcSMichael Zhilin 	struct gpioths_softc	*sc;
312662e30fcSMichael Zhilin 	device_t		 dev;
313662e30fcSMichael Zhilin 
314662e30fcSMichael Zhilin 	dev = (device_t)arg;
315662e30fcSMichael Zhilin 	sc = device_get_softc(dev);
316662e30fcSMichael Zhilin 
317662e30fcSMichael Zhilin 	gpioths_dht_readbytes(device_get_parent(dev), dev);
318662e30fcSMichael Zhilin 	callout_schedule(&sc->callout, GPIOTHS_POLLTIME * hz);
319662e30fcSMichael Zhilin }
320662e30fcSMichael Zhilin 
321662e30fcSMichael Zhilin static int
322662e30fcSMichael Zhilin gpioths_attach(device_t dev)
323662e30fcSMichael Zhilin {
324662e30fcSMichael Zhilin 	struct gpioths_softc	*sc;
325662e30fcSMichael Zhilin 	struct sysctl_ctx_list	*ctx;
326662e30fcSMichael Zhilin 	struct sysctl_oid	*tree;
327662e30fcSMichael Zhilin 
328662e30fcSMichael Zhilin 	sc = device_get_softc(dev);
329662e30fcSMichael Zhilin 	ctx = device_get_sysctl_ctx(dev);
330662e30fcSMichael Zhilin 	tree = device_get_sysctl_tree(dev);
331662e30fcSMichael Zhilin 
332662e30fcSMichael Zhilin 	sc->dev = dev;
333662e30fcSMichael Zhilin 
3349f8df20cSIan Lepore 	/*
3359f8df20cSIan Lepore 	 * Do an initial read so we have correct values for reporting before
3369f8df20cSIan Lepore 	 * registering the sysctls that can access those values.
3379f8df20cSIan Lepore 	 */
3389f8df20cSIan Lepore 	gpioths_dht_readbytes(device_get_parent(dev), dev);
339662e30fcSMichael Zhilin 
34078e70ab9SIan Lepore 	sysctl_add_oid(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "temperature",				\
34178e70ab9SIan Lepore 	    CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE,
342*ce508b36SIan Lepore 	    &sc->temp, 0, sysctl_handle_int, "IK", "temperature", NULL);
343662e30fcSMichael Zhilin 
34478e70ab9SIan Lepore 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "humidity",
34578e70ab9SIan Lepore 	    CTLFLAG_RD, &sc->hum, 0, "relative humidity(%)");
346662e30fcSMichael Zhilin 
34778e70ab9SIan Lepore 	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "fails",
34878e70ab9SIan Lepore 	    CTLFLAG_RD, &sc->fails, 0,
34978e70ab9SIan Lepore 	    "failures since last successful read");
350662e30fcSMichael Zhilin 
3519f8df20cSIan Lepore 	callout_init(&sc->callout, 1);
3529f8df20cSIan Lepore 	callout_reset(&sc->callout, GPIOTHS_POLLTIME * hz, gpioths_poll, dev);
3539f8df20cSIan Lepore 
354662e30fcSMichael Zhilin 	return (0);
355662e30fcSMichael Zhilin }
356662e30fcSMichael Zhilin 
357662e30fcSMichael Zhilin static int
358662e30fcSMichael Zhilin gpioths_detach(device_t dev)
359662e30fcSMichael Zhilin {
3609f8df20cSIan Lepore 	struct gpioths_softc	*sc;
3619f8df20cSIan Lepore 
3629f8df20cSIan Lepore 	sc = device_get_softc(dev);
3639f8df20cSIan Lepore 
3649f8df20cSIan Lepore 	callout_drain(&sc->callout);
365662e30fcSMichael Zhilin 
366662e30fcSMichael Zhilin 	return (0);
367662e30fcSMichael Zhilin }
368662e30fcSMichael Zhilin 
369662e30fcSMichael Zhilin /* Driver bits */
370662e30fcSMichael Zhilin static device_method_t gpioths_methods[] = {
371662e30fcSMichael Zhilin 	/* Device interface */
372662e30fcSMichael Zhilin 	DEVMETHOD(device_probe,			gpioths_probe),
373662e30fcSMichael Zhilin 	DEVMETHOD(device_attach,		gpioths_attach),
374662e30fcSMichael Zhilin 	DEVMETHOD(device_detach,		gpioths_detach),
375662e30fcSMichael Zhilin 
376662e30fcSMichael Zhilin 	DEVMETHOD_END
377662e30fcSMichael Zhilin };
378662e30fcSMichael Zhilin 
379662e30fcSMichael Zhilin DEFINE_CLASS_0(gpioths, gpioths_driver, gpioths_methods, sizeof(struct gpioths_softc));
380662e30fcSMichael Zhilin DRIVER_MODULE(gpioths, gpiobus, gpioths_driver, gpioths_devclass, 0, 0);
381