From owner-svn-src-all@freebsd.org Mon Dec 9 00:30:06 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 863831BFBB0; Mon, 9 Dec 2019 00:30:06 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 47WPGk2z8gz432t; Mon, 9 Dec 2019 00:30:06 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 611D9A708; Mon, 9 Dec 2019 00:30:06 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id xB90U6If055481; Mon, 9 Dec 2019 00:30:06 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id xB90U6oN055480; Mon, 9 Dec 2019 00:30:06 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201912090030.xB90U6oN055480@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Mon, 9 Dec 2019 00:30:06 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r355540 - head/sys/dev/gpio X-SVN-Group: head X-SVN-Commit-Author: ian X-SVN-Commit-Paths: head/sys/dev/gpio X-SVN-Commit-Revision: 355540 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 Dec 2019 00:30:06 -0000 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 -__FBSDID("$FreeBSD$"); - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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= + * + * Or configure via FDT data. */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef FDT +#include +#include + +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);