1*662e30fcSMichael Zhilin /*- 2*662e30fcSMichael Zhilin * Copyright (c) 2016 Michael Zhilin <mizhka@freebsd.org> 3*662e30fcSMichael Zhilin * All rights reserved. 4*662e30fcSMichael Zhilin * 5*662e30fcSMichael Zhilin * Redistribution and use in source and binary forms, with or without 6*662e30fcSMichael Zhilin * modification, are permitted provided that the following conditions 7*662e30fcSMichael Zhilin * are met: 8*662e30fcSMichael Zhilin * 1. Redistributions of source code must retain the above copyright 9*662e30fcSMichael Zhilin * notice, this list of conditions and the following disclaimer. 10*662e30fcSMichael Zhilin * 2. Redistributions in binary form must reproduce the above copyright 11*662e30fcSMichael Zhilin * notice, this list of conditions and the following disclaimer in the 12*662e30fcSMichael Zhilin * documentation and/or other materials provided with the distribution. 13*662e30fcSMichael Zhilin * 14*662e30fcSMichael Zhilin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*662e30fcSMichael Zhilin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*662e30fcSMichael Zhilin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*662e30fcSMichael Zhilin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*662e30fcSMichael Zhilin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*662e30fcSMichael Zhilin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*662e30fcSMichael Zhilin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*662e30fcSMichael Zhilin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*662e30fcSMichael Zhilin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*662e30fcSMichael Zhilin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*662e30fcSMichael Zhilin * SUCH DAMAGE. 25*662e30fcSMichael Zhilin */ 26*662e30fcSMichael Zhilin 27*662e30fcSMichael Zhilin #include <sys/cdefs.h> 28*662e30fcSMichael Zhilin __FBSDID("$FreeBSD$"); 29*662e30fcSMichael Zhilin 30*662e30fcSMichael Zhilin #include <sys/param.h> 31*662e30fcSMichael Zhilin #include <sys/kernel.h> 32*662e30fcSMichael Zhilin #include <sys/bus.h> 33*662e30fcSMichael Zhilin #include <sys/module.h> 34*662e30fcSMichael Zhilin #include <sys/errno.h> 35*662e30fcSMichael Zhilin #include <sys/systm.h> 36*662e30fcSMichael Zhilin #include <sys/sysctl.h> 37*662e30fcSMichael Zhilin 38*662e30fcSMichael Zhilin #include <machine/bus.h> 39*662e30fcSMichael Zhilin #include <sys/rman.h> 40*662e30fcSMichael Zhilin #include <sys/gpio.h> 41*662e30fcSMichael Zhilin #include <machine/resource.h> 42*662e30fcSMichael Zhilin 43*662e30fcSMichael Zhilin #include "gpiobus_if.h" 44*662e30fcSMichael Zhilin 45*662e30fcSMichael Zhilin /* 46*662e30fcSMichael Zhilin * GPIOTHS - Temp/Humidity sensor over GPIO, e.g. DHT11/DHT22 47*662e30fcSMichael Zhilin * This is driver for Temperature & Humidity sensor which provides digital 48*662e30fcSMichael Zhilin * output over single-wire protocol from embedded 8-bit microcontroller. 49*662e30fcSMichael Zhilin * 50*662e30fcSMichael Zhilin * Temp/Humidity sensor can't be discovered automatically, please specify hints 51*662e30fcSMichael Zhilin * as part of loader or kernel configuration: 52*662e30fcSMichael Zhilin * hint.gpioths.0.at="gpiobus0" 53*662e30fcSMichael Zhilin * hint.gpioths.0.pins=<PIN> 54*662e30fcSMichael Zhilin */ 55*662e30fcSMichael Zhilin 56*662e30fcSMichael Zhilin #define GPIOTHS_POLLTIME 5 /* in seconds */ 57*662e30fcSMichael Zhilin 58*662e30fcSMichael Zhilin #define GPIOTHS_DHT_STARTCYCLE 20000 /* 20ms = 20000us */ 59*662e30fcSMichael Zhilin #define GPIOTHS_DHT_TIMEOUT 1000 /* 1ms = 1000us */ 60*662e30fcSMichael Zhilin #define GPIOTHS_DHT_CYCLES 41 61*662e30fcSMichael Zhilin #define GPIOTHS_DHT_ONEBYTEMASK 0xFF 62*662e30fcSMichael Zhilin #define GPIOTHS_DHT_TEMP_SHIFT 8 63*662e30fcSMichael Zhilin #define GPIOTHS_DHT_HUM_SHIFT 24 64*662e30fcSMichael Zhilin 65*662e30fcSMichael Zhilin struct gpioths_softc { 66*662e30fcSMichael Zhilin device_t dev; 67*662e30fcSMichael Zhilin int temp; 68*662e30fcSMichael Zhilin int hum; 69*662e30fcSMichael Zhilin int fails; 70*662e30fcSMichael Zhilin struct sysctl_oid *temp_oid; 71*662e30fcSMichael Zhilin struct sysctl_oid *hum_oid; 72*662e30fcSMichael Zhilin struct sysctl_oid *fails_oid; 73*662e30fcSMichael Zhilin struct callout callout; 74*662e30fcSMichael Zhilin }; 75*662e30fcSMichael Zhilin 76*662e30fcSMichael Zhilin static devclass_t gpioths_devclass; 77*662e30fcSMichael Zhilin 78*662e30fcSMichael Zhilin /* Prototypes */ 79*662e30fcSMichael Zhilin static int gpioths_probe(device_t dev); 80*662e30fcSMichael Zhilin static int gpioths_attach(device_t dev); 81*662e30fcSMichael Zhilin static int gpioths_detach(device_t dev); 82*662e30fcSMichael Zhilin static void gpioths_poll(void *arg); 83*662e30fcSMichael Zhilin static int gpioths_temp_sysctl(SYSCTL_HANDLER_ARGS); 84*662e30fcSMichael Zhilin static int gpioths_hum_sysctl(SYSCTL_HANDLER_ARGS); 85*662e30fcSMichael Zhilin static int gpioths_fails_sysctl(SYSCTL_HANDLER_ARGS); 86*662e30fcSMichael Zhilin 87*662e30fcSMichael Zhilin /* DHT-specific methods */ 88*662e30fcSMichael Zhilin static int gpioths_dht_initread(device_t bus, device_t dev); 89*662e30fcSMichael Zhilin static int gpioths_dht_readbytes(device_t bus, device_t dev); 90*662e30fcSMichael Zhilin static int gpioths_dht_timeuntil(device_t bus, device_t dev, 91*662e30fcSMichael Zhilin uint32_t lev, uint32_t *time); 92*662e30fcSMichael Zhilin 93*662e30fcSMichael Zhilin /* Implementation */ 94*662e30fcSMichael Zhilin static int 95*662e30fcSMichael Zhilin gpioths_probe(device_t dev) 96*662e30fcSMichael Zhilin { 97*662e30fcSMichael Zhilin device_set_desc(dev, "Temperature and Humidity Sensor over GPIO"); 98*662e30fcSMichael Zhilin return (0); 99*662e30fcSMichael Zhilin } 100*662e30fcSMichael Zhilin 101*662e30fcSMichael Zhilin static int 102*662e30fcSMichael Zhilin gpioths_dht_timeuntil(device_t bus, device_t dev, uint32_t lev, uint32_t *time) 103*662e30fcSMichael Zhilin { 104*662e30fcSMichael Zhilin uint32_t cur_level; 105*662e30fcSMichael Zhilin int i; 106*662e30fcSMichael Zhilin 107*662e30fcSMichael Zhilin for (i = 0; i < GPIOTHS_DHT_TIMEOUT; i++) { 108*662e30fcSMichael Zhilin GPIOBUS_PIN_GET(bus, dev, 0, &cur_level); 109*662e30fcSMichael Zhilin if (cur_level == lev) { 110*662e30fcSMichael Zhilin if (time != NULL) 111*662e30fcSMichael Zhilin *time = i; 112*662e30fcSMichael Zhilin return (0); 113*662e30fcSMichael Zhilin } 114*662e30fcSMichael Zhilin DELAY(1); 115*662e30fcSMichael Zhilin } 116*662e30fcSMichael Zhilin 117*662e30fcSMichael Zhilin /* Timeout */ 118*662e30fcSMichael Zhilin return (ETIMEDOUT); 119*662e30fcSMichael Zhilin } 120*662e30fcSMichael Zhilin 121*662e30fcSMichael Zhilin static int 122*662e30fcSMichael Zhilin gpioths_dht_initread(device_t bus, device_t dev) 123*662e30fcSMichael Zhilin { 124*662e30fcSMichael Zhilin int err; 125*662e30fcSMichael Zhilin 126*662e30fcSMichael Zhilin err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_OUTPUT); 127*662e30fcSMichael Zhilin if (err != 0) { 128*662e30fcSMichael Zhilin device_printf(dev, "err(GPIOBUS_PIN_SETFLAGS, OUT) = %d\n", err); 129*662e30fcSMichael Zhilin return (err); 130*662e30fcSMichael Zhilin } 131*662e30fcSMichael Zhilin DELAY(1); 132*662e30fcSMichael Zhilin 133*662e30fcSMichael Zhilin err = GPIOBUS_PIN_SET(bus, dev, 0, GPIO_PIN_LOW); 134*662e30fcSMichael Zhilin if (err != 0) { 135*662e30fcSMichael Zhilin device_printf(dev, "err(GPIOBUS_PIN_SET, LOW) = %d\n", err); 136*662e30fcSMichael Zhilin return (err); 137*662e30fcSMichael Zhilin } 138*662e30fcSMichael Zhilin 139*662e30fcSMichael Zhilin /* 140*662e30fcSMichael Zhilin * According to specifications we need to wait no more than 18ms 141*662e30fcSMichael Zhilin * to start data transfer 142*662e30fcSMichael Zhilin */ 143*662e30fcSMichael Zhilin DELAY(GPIOTHS_DHT_STARTCYCLE); 144*662e30fcSMichael Zhilin err = GPIOBUS_PIN_SET(bus, dev, 0, GPIO_PIN_HIGH); 145*662e30fcSMichael Zhilin if (err != 0) { 146*662e30fcSMichael Zhilin device_printf(dev, "err(GPIOBUS_PIN_SET, HIGH) = %d\n", err); 147*662e30fcSMichael Zhilin return (err); 148*662e30fcSMichael Zhilin } 149*662e30fcSMichael Zhilin 150*662e30fcSMichael Zhilin DELAY(1); 151*662e30fcSMichael Zhilin err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_INPUT) ; 152*662e30fcSMichael Zhilin if (err != 0) { 153*662e30fcSMichael Zhilin device_printf(dev, "err(GPIOBUS_PIN_SETFLAGS, IN) = %d\n", err); 154*662e30fcSMichael Zhilin return (err); 155*662e30fcSMichael Zhilin } 156*662e30fcSMichael Zhilin 157*662e30fcSMichael Zhilin DELAY(1); 158*662e30fcSMichael Zhilin return (0); 159*662e30fcSMichael Zhilin } 160*662e30fcSMichael Zhilin 161*662e30fcSMichael Zhilin static int 162*662e30fcSMichael Zhilin gpioths_dht_readbytes(device_t bus, device_t dev) 163*662e30fcSMichael Zhilin { 164*662e30fcSMichael Zhilin struct gpioths_softc *sc; 165*662e30fcSMichael Zhilin uint32_t calibrations[GPIOTHS_DHT_CYCLES]; 166*662e30fcSMichael Zhilin uint32_t intervals[GPIOTHS_DHT_CYCLES]; 167*662e30fcSMichael Zhilin uint32_t err, avglen, value; 168*662e30fcSMichael Zhilin uint8_t crc, calc; 169*662e30fcSMichael Zhilin int i, offset, size; 170*662e30fcSMichael Zhilin 171*662e30fcSMichael Zhilin sc = device_get_softc(dev); 172*662e30fcSMichael Zhilin 173*662e30fcSMichael Zhilin err = gpioths_dht_initread(bus,dev); 174*662e30fcSMichael Zhilin if (err) { 175*662e30fcSMichael Zhilin device_printf(dev, "gpioths_dht_initread error = %d\n", err); 176*662e30fcSMichael Zhilin goto error; 177*662e30fcSMichael Zhilin } 178*662e30fcSMichael Zhilin 179*662e30fcSMichael Zhilin err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_LOW, NULL); 180*662e30fcSMichael Zhilin if (err) { 181*662e30fcSMichael Zhilin device_printf(dev, "err(START) = %d\n", err); 182*662e30fcSMichael Zhilin goto error; 183*662e30fcSMichael Zhilin } 184*662e30fcSMichael Zhilin 185*662e30fcSMichael Zhilin /* reading - 41 cycles */ 186*662e30fcSMichael Zhilin for (i = 0; i < GPIOTHS_DHT_CYCLES; i++) { 187*662e30fcSMichael Zhilin err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_HIGH, 188*662e30fcSMichael Zhilin &calibrations[i]); 189*662e30fcSMichael Zhilin if (err) { 190*662e30fcSMichael Zhilin device_printf(dev, "err(CAL, %d) = %d\n", i, err); 191*662e30fcSMichael Zhilin goto error; 192*662e30fcSMichael Zhilin } 193*662e30fcSMichael Zhilin err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_LOW, 194*662e30fcSMichael Zhilin &intervals[i]); 195*662e30fcSMichael Zhilin if (err) { 196*662e30fcSMichael Zhilin device_printf(dev, "err(INTERVAL, %d) = %d\n", i, err); 197*662e30fcSMichael Zhilin goto error; 198*662e30fcSMichael Zhilin } 199*662e30fcSMichael Zhilin } 200*662e30fcSMichael Zhilin 201*662e30fcSMichael Zhilin err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_OUTPUT); 202*662e30fcSMichael Zhilin if (err != 0) { 203*662e30fcSMichael Zhilin device_printf(dev, "err(FINAL_SETFLAGS, OUT) = %d\n", err); 204*662e30fcSMichael Zhilin goto error; 205*662e30fcSMichael Zhilin } 206*662e30fcSMichael Zhilin DELAY(1); 207*662e30fcSMichael Zhilin 208*662e30fcSMichael Zhilin /* Calculate average data calibration cycle length */ 209*662e30fcSMichael Zhilin avglen = 0; 210*662e30fcSMichael Zhilin for (i = 1; i < GPIOTHS_DHT_CYCLES; i++) 211*662e30fcSMichael Zhilin avglen += calibrations[i]; 212*662e30fcSMichael Zhilin 213*662e30fcSMichael Zhilin avglen = avglen / (GPIOTHS_DHT_CYCLES - 1); 214*662e30fcSMichael Zhilin 215*662e30fcSMichael Zhilin /* Calculate data */ 216*662e30fcSMichael Zhilin value = 0; 217*662e30fcSMichael Zhilin offset = 1; 218*662e30fcSMichael Zhilin size = sizeof(value) * 8; 219*662e30fcSMichael Zhilin for (i = offset; i < size + offset; i++) { 220*662e30fcSMichael Zhilin value <<= 1; 221*662e30fcSMichael Zhilin if (intervals[i] > avglen) 222*662e30fcSMichael Zhilin value += 1; 223*662e30fcSMichael Zhilin } 224*662e30fcSMichael Zhilin 225*662e30fcSMichael Zhilin /* Calculate CRC */ 226*662e30fcSMichael Zhilin crc = 0; 227*662e30fcSMichael Zhilin offset = sizeof(value) * 8 + 1; 228*662e30fcSMichael Zhilin size = sizeof(crc) * 8; 229*662e30fcSMichael Zhilin for (i = offset; i < size + offset; i++) { 230*662e30fcSMichael Zhilin crc <<= 1; 231*662e30fcSMichael Zhilin if (intervals[i] > avglen) 232*662e30fcSMichael Zhilin crc += 1; 233*662e30fcSMichael Zhilin } 234*662e30fcSMichael Zhilin 235*662e30fcSMichael Zhilin calc = 0; 236*662e30fcSMichael Zhilin for (i = 0; i < sizeof(value); i++) 237*662e30fcSMichael Zhilin calc += (value >> (8*i)) & GPIOTHS_DHT_ONEBYTEMASK; 238*662e30fcSMichael Zhilin 239*662e30fcSMichael Zhilin #ifdef GPIOTHS_DEBUG 240*662e30fcSMichael Zhilin /* Debug bits */ 241*662e30fcSMichael Zhilin for (i = 0; i < GPIOTHS_DHT_CYCLES; i++) 242*662e30fcSMichael Zhilin device_printf(dev, "%d: %d %d\n", i, calibrations[i], 243*662e30fcSMichael Zhilin intervals[i]); 244*662e30fcSMichael Zhilin 245*662e30fcSMichael Zhilin device_printf(dev, "len=%d, data=%x, crc=%x/%x\n", avglen, value, crc, 246*662e30fcSMichael Zhilin calc); 247*662e30fcSMichael Zhilin #endif /* GPIOTHS_DEBUG */ 248*662e30fcSMichael Zhilin 249*662e30fcSMichael Zhilin /* CRC check */ 250*662e30fcSMichael Zhilin if (calc != crc) { 251*662e30fcSMichael Zhilin err = -1; 252*662e30fcSMichael Zhilin goto error; 253*662e30fcSMichael Zhilin } 254*662e30fcSMichael Zhilin 255*662e30fcSMichael Zhilin sc->fails = 0; 256*662e30fcSMichael Zhilin sc->temp = (value >> GPIOTHS_DHT_TEMP_SHIFT) & GPIOTHS_DHT_ONEBYTEMASK; 257*662e30fcSMichael Zhilin sc->hum = (value >> GPIOTHS_DHT_HUM_SHIFT) & GPIOTHS_DHT_ONEBYTEMASK; 258*662e30fcSMichael Zhilin 259*662e30fcSMichael Zhilin #ifdef GPIOTHS_DEBUG 260*662e30fcSMichael Zhilin /* Debug bits */ 261*662e30fcSMichael Zhilin device_printf(dev, "fails=%d, temp=%d, hum=%d\n", sc->fails, 262*662e30fcSMichael Zhilin sc->temp, sc->hum); 263*662e30fcSMichael Zhilin #endif /* GPIOTHS_DEBUG */ 264*662e30fcSMichael Zhilin 265*662e30fcSMichael Zhilin return (0); 266*662e30fcSMichael Zhilin error: 267*662e30fcSMichael Zhilin sc->fails++; 268*662e30fcSMichael Zhilin return (err); 269*662e30fcSMichael Zhilin } 270*662e30fcSMichael Zhilin 271*662e30fcSMichael Zhilin static void 272*662e30fcSMichael Zhilin gpioths_poll(void *arg) 273*662e30fcSMichael Zhilin { 274*662e30fcSMichael Zhilin struct gpioths_softc *sc; 275*662e30fcSMichael Zhilin device_t dev; 276*662e30fcSMichael Zhilin 277*662e30fcSMichael Zhilin dev = (device_t)arg; 278*662e30fcSMichael Zhilin sc = device_get_softc(dev); 279*662e30fcSMichael Zhilin 280*662e30fcSMichael Zhilin gpioths_dht_readbytes(device_get_parent(dev), dev); 281*662e30fcSMichael Zhilin callout_schedule(&sc->callout, GPIOTHS_POLLTIME * hz); 282*662e30fcSMichael Zhilin } 283*662e30fcSMichael Zhilin 284*662e30fcSMichael Zhilin static int 285*662e30fcSMichael Zhilin gpioths_temp_sysctl(SYSCTL_HANDLER_ARGS) 286*662e30fcSMichael Zhilin { 287*662e30fcSMichael Zhilin struct gpioths_softc *sc; 288*662e30fcSMichael Zhilin int value; 289*662e30fcSMichael Zhilin 290*662e30fcSMichael Zhilin sc = (struct gpioths_softc*)arg1; 291*662e30fcSMichael Zhilin value = sc->temp; 292*662e30fcSMichael Zhilin 293*662e30fcSMichael Zhilin return (sysctl_handle_int(oidp, &value, 0, req)); 294*662e30fcSMichael Zhilin } 295*662e30fcSMichael Zhilin 296*662e30fcSMichael Zhilin static int 297*662e30fcSMichael Zhilin gpioths_hum_sysctl(SYSCTL_HANDLER_ARGS) 298*662e30fcSMichael Zhilin { 299*662e30fcSMichael Zhilin struct gpioths_softc *sc; 300*662e30fcSMichael Zhilin int value; 301*662e30fcSMichael Zhilin 302*662e30fcSMichael Zhilin sc = (struct gpioths_softc*)arg1; 303*662e30fcSMichael Zhilin value = sc->hum; 304*662e30fcSMichael Zhilin 305*662e30fcSMichael Zhilin return (sysctl_handle_int(oidp, &value, 0, req)); 306*662e30fcSMichael Zhilin } 307*662e30fcSMichael Zhilin 308*662e30fcSMichael Zhilin 309*662e30fcSMichael Zhilin static int 310*662e30fcSMichael Zhilin gpioths_fails_sysctl(SYSCTL_HANDLER_ARGS) 311*662e30fcSMichael Zhilin { 312*662e30fcSMichael Zhilin struct gpioths_softc *sc; 313*662e30fcSMichael Zhilin int value; 314*662e30fcSMichael Zhilin 315*662e30fcSMichael Zhilin sc = (struct gpioths_softc*)arg1; 316*662e30fcSMichael Zhilin value = sc->fails; 317*662e30fcSMichael Zhilin 318*662e30fcSMichael Zhilin return (sysctl_handle_int(oidp, &value, 0, req)); 319*662e30fcSMichael Zhilin } 320*662e30fcSMichael Zhilin 321*662e30fcSMichael Zhilin static int 322*662e30fcSMichael Zhilin gpioths_attach(device_t dev) 323*662e30fcSMichael Zhilin { 324*662e30fcSMichael Zhilin struct gpioths_softc *sc; 325*662e30fcSMichael Zhilin struct sysctl_ctx_list *ctx; 326*662e30fcSMichael Zhilin struct sysctl_oid *tree; 327*662e30fcSMichael Zhilin 328*662e30fcSMichael Zhilin sc = device_get_softc(dev); 329*662e30fcSMichael Zhilin ctx = device_get_sysctl_ctx(dev); 330*662e30fcSMichael Zhilin tree = device_get_sysctl_tree(dev); 331*662e30fcSMichael Zhilin 332*662e30fcSMichael Zhilin sc->dev = dev; 333*662e30fcSMichael Zhilin 334*662e30fcSMichael Zhilin callout_init(&sc->callout, 1); 335*662e30fcSMichael Zhilin callout_reset(&sc->callout, GPIOTHS_POLLTIME * hz, gpioths_poll, dev); 336*662e30fcSMichael Zhilin 337*662e30fcSMichael Zhilin sc->temp_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 338*662e30fcSMichael Zhilin "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0, 339*662e30fcSMichael Zhilin gpioths_temp_sysctl, "I", "temperature(C)"); 340*662e30fcSMichael Zhilin 341*662e30fcSMichael Zhilin sc->hum_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 342*662e30fcSMichael Zhilin "humidity", CTLTYPE_INT | CTLFLAG_RD, sc, 0, 343*662e30fcSMichael Zhilin gpioths_hum_sysctl, "I", "humidity(%)"); 344*662e30fcSMichael Zhilin 345*662e30fcSMichael Zhilin sc->fails_oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 346*662e30fcSMichael Zhilin "fails", CTLTYPE_INT | CTLFLAG_RD, sc, 0, 347*662e30fcSMichael Zhilin gpioths_fails_sysctl, "I", "fails since last successful read"); 348*662e30fcSMichael Zhilin 349*662e30fcSMichael Zhilin return (0); 350*662e30fcSMichael Zhilin } 351*662e30fcSMichael Zhilin 352*662e30fcSMichael Zhilin static int 353*662e30fcSMichael Zhilin gpioths_detach(device_t dev) 354*662e30fcSMichael Zhilin { 355*662e30fcSMichael Zhilin 356*662e30fcSMichael Zhilin return (0); 357*662e30fcSMichael Zhilin } 358*662e30fcSMichael Zhilin 359*662e30fcSMichael Zhilin /* DDB bits */ 360*662e30fcSMichael Zhilin #include "opt_ddb.h" 361*662e30fcSMichael Zhilin #ifdef DDB 362*662e30fcSMichael Zhilin #include <ddb/ddb.h> 363*662e30fcSMichael Zhilin #include <ddb/db_lex.h> 364*662e30fcSMichael Zhilin #include <sys/cons.h> 365*662e30fcSMichael Zhilin 366*662e30fcSMichael Zhilin static struct command_table db_gpioths_table = LIST_HEAD_INITIALIZER(db_t4_table); 367*662e30fcSMichael Zhilin _DB_SET(_show, gpioths, NULL, db_show_table, 0, &db_gpioths_table); 368*662e30fcSMichael Zhilin 369*662e30fcSMichael Zhilin DB_FUNC(read, db_show_gpiothsread, db_gpioths_table, CS_OWN, NULL) 370*662e30fcSMichael Zhilin { 371*662e30fcSMichael Zhilin device_t dev; 372*662e30fcSMichael Zhilin int t; 373*662e30fcSMichael Zhilin int init; 374*662e30fcSMichael Zhilin 375*662e30fcSMichael Zhilin init = 0; 376*662e30fcSMichael Zhilin t = db_read_token(); 377*662e30fcSMichael Zhilin if (t == tIDENT) { 378*662e30fcSMichael Zhilin dev = device_lookup_by_name(db_tok_string); 379*662e30fcSMichael Zhilin init = 1; 380*662e30fcSMichael Zhilin } 381*662e30fcSMichael Zhilin 382*662e30fcSMichael Zhilin db_skip_to_eol(); 383*662e30fcSMichael Zhilin 384*662e30fcSMichael Zhilin if (init) 385*662e30fcSMichael Zhilin db_printf("read: 0x%x\n", 386*662e30fcSMichael Zhilin gpioths_dht_readbytes(dev, device_get_parent(dev))); 387*662e30fcSMichael Zhilin else 388*662e30fcSMichael Zhilin db_printf("usage: show gpioths read <gpiothsdevice>\n"); 389*662e30fcSMichael Zhilin 390*662e30fcSMichael Zhilin return; 391*662e30fcSMichael Zhilin } 392*662e30fcSMichael Zhilin #endif /* DDB */ 393*662e30fcSMichael Zhilin 394*662e30fcSMichael Zhilin /* Driver bits */ 395*662e30fcSMichael Zhilin static device_method_t gpioths_methods[] = { 396*662e30fcSMichael Zhilin /* Device interface */ 397*662e30fcSMichael Zhilin DEVMETHOD(device_probe, gpioths_probe), 398*662e30fcSMichael Zhilin DEVMETHOD(device_attach, gpioths_attach), 399*662e30fcSMichael Zhilin DEVMETHOD(device_detach, gpioths_detach), 400*662e30fcSMichael Zhilin 401*662e30fcSMichael Zhilin DEVMETHOD_END 402*662e30fcSMichael Zhilin }; 403*662e30fcSMichael Zhilin 404*662e30fcSMichael Zhilin DEFINE_CLASS_0(gpioths, gpioths_driver, gpioths_methods, sizeof(struct gpioths_softc)); 405*662e30fcSMichael Zhilin DRIVER_MODULE(gpioths, gpiobus, gpioths_driver, gpioths_devclass, 0, 0); 406