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