Author: ian
Date: Mon Dec  9 00:30:05 2019
New Revision: 355540
URL: https://svnweb.freebsd.org/changeset/base/355540

Log:
  Add FDT support to the gpioths driver.  It now uses the newer gpio_pin_*()
  API and can attach based on either hints or fdt data.

Modified:
  head/sys/dev/gpio/gpioths.c

Modified: head/sys/dev/gpio/gpioths.c
==============================================================================
--- head/sys/dev/gpio/gpioths.c Sun Dec  8 22:36:37 2019        (r355539)
+++ head/sys/dev/gpio/gpioths.c Mon Dec  9 00:30:05 2019        (r355540)
@@ -24,28 +24,12 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/kernel.h>
-#include <sys/bus.h>
-#include <sys/module.h>
-#include <sys/errno.h>
-#include <sys/systm.h>
-#include <sys/sysctl.h>
-
-#include <machine/bus.h>
-#include <sys/rman.h>
-#include <sys/gpio.h>
-#include <machine/resource.h>
-
-#include "gpiobus_if.h"
-
 /*
- * GPIOTHS - Temp/Humidity sensor over GPIO, e.g. DHT11/DHT22
+ * GPIOTHS - Temp/Humidity sensor over GPIO.
+ *
  * This is driver for Temperature & Humidity sensor which provides digital
  * output over single-wire protocol from embedded 8-bit microcontroller.
+ * Note that uses a custom single-wire protocol, it is not One-wire(tm).
  * 
  * This driver supports the following chips:
  *   DHT11:  Temp   0c to 50c +-2.0c, Humidity 20% to  90% +-5%
@@ -59,8 +43,38 @@ __FBSDID("$FreeBSD$");
  * as part of loader or kernel configuration:
  *     hint.gpioths.0.at="gpiobus0"
  *     hint.gpioths.0.pins=<PIN>
+ *
+ * Or configure via FDT data.
  */
 
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/gpio.h>
+#include <sys/module.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+#include <sys/sysctl.h>
+
+#include <dev/gpio/gpiobusvar.h>
+
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+static struct ofw_compat_data compat_data[] = {
+       {"dht11",  true},
+       {NULL,     false}
+};
+OFWBUS_PNP_INFO(compat_data);
+SIMPLEBUS_PNP_INFO(compat_data);
+#endif /* FDT */
+
+#define        PIN_IDX 0                       /* Use the first/only 
configured pin. */
+
 #define        GPIOTHS_POLLTIME        5       /* in seconds */
 
 #define        GPIOTHS_DHT_STARTCYCLE  20000   /* 20ms = 20000us */
@@ -70,40 +84,44 @@ __FBSDID("$FreeBSD$");
 
 struct gpioths_softc {
        device_t                 dev;
+       gpio_pin_t               pin;
        int                      temp;
        int                      hum;
        int                      fails;
        struct callout           callout;
 };
 
-/* Prototypes */
-static int             gpioths_probe(device_t dev);
-static int             gpioths_attach(device_t dev);
-static int             gpioths_detach(device_t dev);
-static void            gpioths_poll(void *arg);
-
-/* DHT-specific methods */
-static int             gpioths_dht_initread(device_t bus, device_t dev);
-static int             gpioths_dht_readbytes(device_t bus, device_t dev);
-static int             gpioths_dht_timeuntil(device_t bus, device_t dev,
-                           uint32_t lev, uint32_t *time);
-
-/* Implementation */
 static int
 gpioths_probe(device_t dev)
 {
-       device_set_desc(dev, "Temperature and Humidity Sensor over GPIO");
-       return (0);
+       int rv;
+
+       /*
+        * By default we only bid to attach if specifically added by our parent
+        * (usually via hint.gpioths.#.at=busname).  On FDT systems we bid as
+        * the default driver based on being configured in the FDT data.
+        */
+       rv = BUS_PROBE_NOWILDCARD;
+
+#ifdef FDT
+       if (ofw_bus_status_okay(dev) &&
+           ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+               rv = BUS_PROBE_DEFAULT;
+#endif
+
+       device_set_desc(dev, "DHT11/DHT22 Temperature and Humidity Sensor");
+
+       return (rv);
 }
 
 static int
-gpioths_dht_timeuntil(device_t bus, device_t dev, uint32_t lev, uint32_t *time)
+gpioths_dht_timeuntil(struct gpioths_softc *sc, bool lev, uint32_t *time)
 {
-       uint32_t        cur_level;
+       bool            cur_level;
        int             i;
 
        for (i = 0; i < GPIOTHS_DHT_TIMEOUT; i++) {
-               GPIOBUS_PIN_GET(bus, dev, 0, &cur_level);
+               gpio_pin_is_active(sc->pin, &cur_level);
                if (cur_level == lev) {
                        if (time != NULL)
                                *time = i;
@@ -116,93 +134,54 @@ gpioths_dht_timeuntil(device_t bus, device_t dev, uint
        return (ETIMEDOUT);
 }
 
-static int
-gpioths_dht_initread(device_t bus, device_t dev)
+static void
+gpioths_dht_initread(struct gpioths_softc *sc)
 {
-       int     err;
 
-       err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_OUTPUT);
-       if (err != 0) {
-               device_printf(dev, "err(GPIOBUS_PIN_SETFLAGS, OUT) = %d\n", 
err);
-               return (err);
-       }
-       DELAY(1);
-
-       err = GPIOBUS_PIN_SET(bus, dev, 0, GPIO_PIN_LOW);
-       if (err != 0) {
-               device_printf(dev, "err(GPIOBUS_PIN_SET, LOW) = %d\n", err);
-               return (err);
-       }
-
        /*
-        * According to specifications we need to wait no more than 18ms
-        * to start data transfer
+        * According to specifications we need to drive the data line low for at
+        * least 20ms then drive it high, to wake up the chip and signal it to
+        * send a measurement. After sending this start signal, we switch the
+        * pin back to input so the device can begin talking to us.
         */
+       gpio_pin_setflags(sc->pin, GPIO_PIN_OUTPUT);
+       gpio_pin_set_active(sc->pin, false);
        DELAY(GPIOTHS_DHT_STARTCYCLE);
-       err = GPIOBUS_PIN_SET(bus, dev, 0, GPIO_PIN_HIGH);
-       if (err != 0) {
-               device_printf(dev, "err(GPIOBUS_PIN_SET, HIGH) = %d\n", err);
-               return (err);
-       }
-
-       DELAY(1);
-       err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_INPUT) ;
-       if (err != 0) {
-               device_printf(dev, "err(GPIOBUS_PIN_SETFLAGS, IN) = %d\n", err);
-               return (err);
-       }
-
-       DELAY(1);
-       return (0);
+       gpio_pin_set_active(sc->pin, true);
+       gpio_pin_setflags(sc->pin, GPIO_PIN_INPUT);
 }
 
 static int
-gpioths_dht_readbytes(device_t bus, device_t dev)
+gpioths_dht_readbytes(struct gpioths_softc *sc)
 {
-       struct gpioths_softc    *sc;
        uint32_t                 calibrations[GPIOTHS_DHT_CYCLES];
        uint32_t                 intervals[GPIOTHS_DHT_CYCLES];
        uint32_t                 err, avglen, value;
        uint8_t                  crc, calc;
        int                      i, negmul, offset, size, tmphi, tmplo;
 
-       sc = device_get_softc(dev);
-
-       err = gpioths_dht_initread(bus,dev);
+       gpioths_dht_initread(sc);
+       
+       err = gpioths_dht_timeuntil(sc, false, NULL);
        if (err) {
-               device_printf(dev, "gpioths_dht_initread error = %d\n", err);
+               device_printf(sc->dev, "err(START) = %d\n", err);
                goto error;
        }
 
-       err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_LOW, NULL);
-       if (err) {
-               device_printf(dev, "err(START) = %d\n", err);
-               goto error;
-       }
-
        /* reading - 41 cycles */
        for (i = 0; i < GPIOTHS_DHT_CYCLES; i++) {
-               err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_HIGH,
-                         &calibrations[i]);
+               err = gpioths_dht_timeuntil(sc, true, &calibrations[i]);
                if (err) {
-                       device_printf(dev, "err(CAL, %d) = %d\n", i, err);
+                       device_printf(sc->dev, "err(CAL, %d) = %d\n", i, err);
                        goto error;
                }
-               err = gpioths_dht_timeuntil(bus, dev, GPIO_PIN_LOW,
-                         &intervals[i]);
+               err = gpioths_dht_timeuntil(sc, false, &intervals[i]);
                if (err) {
-                       device_printf(dev, "err(INTERVAL, %d) = %d\n", i, err);
+                       device_printf(sc->dev, "err(INTERVAL, %d) = %d\n", i, 
err);
                        goto error;
                }
        }
 
-       err = GPIOBUS_PIN_SETFLAGS(bus, dev, 0, GPIO_PIN_INPUT);
-       if (err != 0) {
-               device_printf(dev, "err(FINAL_SETFLAGS, IN) = %d\n", err);
-               goto error;
-       }
-       DELAY(1);
-
        /* Calculate average data calibration cycle length */
        avglen = 0;
        for (i = 1; i < GPIOTHS_DHT_CYCLES; i++)
@@ -271,8 +250,8 @@ gpioths_dht_readbytes(device_t bus, device_t dev)
         * the upper bits of its 16-bit humidity.  A DHT11/12 should not report
         * a value lower than 20.  To allow for the possibility that a device
         * could report a value slightly out of its sensitivity range, we split
-        * the difference and say if the value is greater than 10 it cannot be a
-        * DHT22 (that would be a humidity over 256%).
+        * the difference and say if the value is greater than 10 it must be a
+        * DHT11/12 (that would be a humidity over 256% on a DHT21/22).
         */
 #define        DK_OFFSET 2731 /* Offset between K and C, in decikelvins. */
        if ((value >> 24) > 10) {
@@ -307,12 +286,10 @@ static void
 gpioths_poll(void *arg)
 {
        struct gpioths_softc    *sc;
-       device_t                 dev;
 
-       dev = (device_t)arg;
-       sc = device_get_softc(dev);
+       sc = (struct gpioths_softc *)arg;
 
-       gpioths_dht_readbytes(device_get_parent(dev), dev);
+       gpioths_dht_readbytes(sc);
        callout_schedule(&sc->callout, GPIOTHS_POLLTIME * hz);
 }
 
@@ -322,6 +299,7 @@ gpioths_attach(device_t dev)
        struct gpioths_softc    *sc;
        struct sysctl_ctx_list  *ctx;
        struct sysctl_oid       *tree;
+       int err;
 
        sc = device_get_softc(dev);
        ctx = device_get_sysctl_ctx(dev);
@@ -329,11 +307,55 @@ gpioths_attach(device_t dev)
 
        sc->dev = dev;
 
+#ifdef FDT
+       /* Try to configure our pin from fdt data on fdt-based systems. */
+       err = gpio_pin_get_by_ofw_idx(dev, ofw_bus_get_node(dev), PIN_IDX,
+           &sc->pin);
+#else
+       err = ENOENT;
+#endif
+       /*
+        * If we didn't get configured by fdt data and our parent is gpiobus,
+        * see if we can be configured by the bus (allows hinted attachment even
+        * on fdt-based systems).
+        */
+       if (err != 0 &&
+           strcmp("gpiobus", device_get_name(device_get_parent(dev))) == 0)
+               err = gpio_pin_get_by_child_index(dev, PIN_IDX, &sc->pin);
+
+       /* If we didn't get configured by either method, whine and punt. */
+       if (err != 0) {
+               device_printf(sc->dev,
+                   "cannot acquire gpio pin (config error)\n");
+               return (err);
+       }
+
+       /*
+        * Ensure we have control of our pin, and preset the data line to its
+        * idle condition (high).  Leave the line in input mode, relying on the
+        * external pullup to keep the line high while idle.
+        */
+       err = gpio_pin_setflags(sc->pin, GPIO_PIN_OUTPUT);
+       if (err != 0) {
+               device_printf(dev, "gpio_pin_setflags(OUT) = %d\n", err);
+               return (err);
+       }
+       err = gpio_pin_set_active(sc->pin, true);
+       if (err != 0) {
+               device_printf(dev, "gpio_pin_set_active(false) = %d\n", err);
+               return (err);
+       }
+       err = gpio_pin_setflags(sc->pin, GPIO_PIN_INPUT);
+       if (err != 0) {
+               device_printf(dev, "gpio_pin_setflags(IN) = %d\n", err);
+               return (err);
+       }
+
        /* 
         * Do an initial read so we have correct values for reporting before
         * registering the sysctls that can access those values.
         */
-       gpioths_dht_readbytes(device_get_parent(dev), dev);
+       gpioths_dht_readbytes(sc);
 
        sysctl_add_oid(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "temperature",     
                        \
            CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE,
@@ -347,7 +369,7 @@ gpioths_attach(device_t dev)
            "failures since last successful read");
 
        callout_init(&sc->callout, 1);
-       callout_reset(&sc->callout, GPIOTHS_POLLTIME * hz, gpioths_poll, dev);
+       callout_reset(&sc->callout, GPIOTHS_POLLTIME * hz, gpioths_poll, sc);
 
        return (0);
 }
@@ -358,7 +380,7 @@ gpioths_detach(device_t dev)
        struct gpioths_softc    *sc;
 
        sc = device_get_softc(dev);
-
+       gpio_pin_release(sc->pin);
        callout_drain(&sc->callout);
 
        return (0);
@@ -377,5 +399,10 @@ static device_method_t gpioths_methods[] = {
 static devclass_t gpioths_devclass;
 
 DEFINE_CLASS_0(gpioths, gpioths_driver, gpioths_methods, sizeof(struct 
gpioths_softc));
+
+#ifdef FDT
+DRIVER_MODULE(gpioths, simplebus, gpioths_driver, gpioths_devclass, 0, 0);
+#endif
+
 DRIVER_MODULE(gpioths, gpiobus, gpioths_driver, gpioths_devclass, 0, 0);
 MODULE_DEPEND(gpioths, gpiobus, 1, 1, 1);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to