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> 63989da27eSIan 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; 94989da27eSIan Lepore struct timeout_task task; 95989da27eSIan 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); 153989da27eSIan 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++) 223*aa063061SBrad Davis device_printf(sc->dev, "%d: %d %d\n", i, calibrations[i], 224662e30fcSMichael Zhilin intervals[i]); 225662e30fcSMichael Zhilin 226*aa063061SBrad Davis device_printf(sc->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 290989da27eSIan 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); 297989da27eSIan Lepore if (!sc->detaching) 298989da27eSIan Lepore taskqueue_enqueue_timeout_sbt(taskqueue_thread, &sc->task, 299989da27eSIan 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 316989da27eSIan Lepore TIMEOUT_TASK_INIT(taskqueue_thread, &sc->task, 0, gpioths_poll, sc); 317989da27eSIan 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 364989da27eSIan Lepore * registering the sysctls that can access those values. This also 365989da27eSIan Lepore * schedules the periodic polling the driver does every few seconds to 366989da27eSIan Lepore * update the sysctl variables. 3679f8df20cSIan Lepore */ 368989da27eSIan 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); 391989da27eSIan Lepore sc->detaching = true; 392989da27eSIan Lepore while (taskqueue_cancel_timeout(taskqueue_thread, &sc->task, NULL) != 0) 393989da27eSIan 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