aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorIan Lepore <ian@FreeBSD.org>2019-12-17 15:56:48 +0000
committerIan Lepore <ian@FreeBSD.org>2019-12-17 15:56:48 +0000
commitc7b0edf219290a9a77a4c59987b5783061ae19c9 (patch)
tree7aeb3022975f15d81015a9fe19472ac6993b38ae /sys
parent98d97cdec785593d6d0c33ccef9493b3f9d3e11e (diff)
downloadsrc-c7b0edf219290a9a77a4c59987b5783061ae19c9.tar.gz
src-c7b0edf219290a9a77a4c59987b5783061ae19c9.zip
Update owc_gpiobus (one-wire over gpio) to the modern gpio_pin interface.
It used to be required that a device be a child of gpiobus(4) to manipulate gpio pins. That requirement didn't work well for FDT-based systems with many cross-hierarchy users of gpio, so a more modern framework was created that removed the old hierarchy requirement. These changes adapt the owc_gpiobus driver to use the newer gpio_pin_* functions to acquire, release, and manipulate gpio pins. This allows a single driver to work for both hinted-attachment and fdt-based systems, and removes the requirement that any one-wire fdt nodes must appear at the root of the devicetree. Differential Revision: https://reviews.freebsd.org/D22710
Notes
Notes: svn path=/head/; revision=355858
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ow/owc_gpiobus.c193
1 files changed, 88 insertions, 105 deletions
diff --git a/sys/dev/ow/owc_gpiobus.c b/sys/dev/ow/owc_gpiobus.c
index c410e17d10f7..4b8b2ab6f99e 100644
--- a/sys/dev/ow/owc_gpiobus.c
+++ b/sys/dev/ow/owc_gpiobus.c
@@ -38,16 +38,20 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/mutex.h>
+#include <dev/gpio/gpiobusvar.h>
+#include <dev/ow/owll.h>
+
#ifdef FDT
-#include <dev/fdt/fdt_common.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#endif
-
-#include <dev/gpio/gpiobusvar.h>
-#include "gpiobus_if.h"
-#include <dev/ow/owll.h>
+static struct ofw_compat_data compat_data[] = {
+ {"w1-gpio", true},
+ {NULL, false}
+};
+OFWBUS_PNP_INFO(compat_data);
+SIMPLEBUS_PNP_INFO(compat_data);
+#endif /* FDT */
#define OW_PIN 0
@@ -61,7 +65,7 @@ __FBSDID("$FreeBSD$");
struct owc_gpiobus_softc
{
device_t sc_dev;
- device_t sc_busdev;
+ gpio_pin_t sc_pin;
struct mtx sc_mtx;
};
@@ -69,68 +73,69 @@ static int owc_gpiobus_probe(device_t);
static int owc_gpiobus_attach(device_t);
static int owc_gpiobus_detach(device_t);
-#ifdef FDT
-static void
-owc_gpiobus_identify(driver_t *driver, device_t bus)
+static int
+owc_gpiobus_probe(device_t dev)
{
- phandle_t w1, root;
+ int rv;
/*
- * Find all the 1-wire bus pseudo-nodes that are
- * at the top level of the FDT. Would be nice to
- * somehow preserve the node name of these busses,
- * but there's no good place to put it. The driver's
- * name is used for the device name, and the 1-wire
- * bus overwrites the description.
+ * By default we only bid to attach if specifically added by our parent
+ * (usually via hint.owc_gpiobus.#.at=busname). On FDT systems we bid
+ * as the default driver based on being configured in the FDT data.
*/
- root = OF_finddevice("/");
- if (root == -1)
- return;
- for (w1 = OF_child(root); w1 != 0; w1 = OF_peer(w1)) {
- if (!fdt_is_compatible_strict(w1, "w1-gpio"))
- continue;
- if (!OF_hasprop(w1, "gpios"))
- continue;
- ofw_gpiobus_add_fdt_child(bus, driver->name, w1);
- }
-}
-#endif
+ rv = BUS_PROBE_NOWILDCARD;
-static int
-owc_gpiobus_probe(device_t dev)
-{
#ifdef FDT
- if (!ofw_bus_status_okay(dev))
- return (ENXIO);
+ if (ofw_bus_status_okay(dev) &&
+ ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+ rv = BUS_PROBE_DEFAULT;
+#endif
- if (ofw_bus_is_compatible(dev, "w1-gpio")) {
- device_set_desc(dev, "FDT GPIO attached one-wire bus");
- return (BUS_PROBE_DEFAULT);
- }
+ device_set_desc(dev, "GPIO one-wire bus");
- return (ENXIO);
-#else
- device_set_desc(dev, "GPIO attached one-wire bus");
- return 0;
-#endif
+ return (rv);
}
static int
owc_gpiobus_attach(device_t dev)
{
struct owc_gpiobus_softc *sc;
- device_t *kids;
- int nkid;
+ int err;
sc = device_get_softc(dev);
sc->sc_dev = dev;
- sc->sc_busdev = device_get_parent(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), OW_PIN,
+ &sc->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, OW_PIN, &sc->sc_pin);
+
+ /* If we didn't get configured by either method, whine and punt. */
+ if (err != 0) {
+ device_printf(sc->sc_dev,
+ "cannot acquire gpio pin (config error)\n");
+ return (err);
+ }
+
OWC_GPIOBUS_LOCK_INIT(sc);
- nkid = 0;
- if (device_get_children(dev, &kids, &nkid) == 0)
- free(kids, M_TEMP);
- if (nkid == 0)
- device_add_child(dev, "ow", -1);
+
+ /*
+ * Add the ow bus as a child, but defer probing and attaching it until
+ * interrupts work, because we can't do IO for them until we can read
+ * the system timecounter (which initializes after device attachments).
+ */
+ device_add_child(sc->sc_dev, "ow", -1);
return (bus_delayed_attach_children(dev));
}
@@ -138,10 +143,16 @@ static int
owc_gpiobus_detach(device_t dev)
{
struct owc_gpiobus_softc *sc;
+ int err;
sc = device_get_softc(dev);
+
+ if ((err = device_delete_children(dev)) != 0)
+ return (err);
+
+ gpio_pin_release(sc->sc_pin);
OWC_GPIOBUS_LOCK_DESTROY(sc);
- bus_generic_detach(dev);
+
return (0);
}
@@ -154,18 +165,10 @@ owc_gpiobus_detach(device_t dev)
* These macros let what why we're doing stuff shine in the code
* below, and let the how be confined to here.
*/
-#define GETBUS(sc) GPIOBUS_ACQUIRE_BUS((sc)->sc_busdev, \
- (sc)->sc_dev, GPIOBUS_WAIT)
-#define RELBUS(sc) GPIOBUS_RELEASE_BUS((sc)->sc_busdev, \
- (sc)->sc_dev)
-#define OUTPIN(sc) GPIOBUS_PIN_SETFLAGS((sc)->sc_busdev, \
- (sc)->sc_dev, OW_PIN, GPIO_PIN_OUTPUT)
-#define INPIN(sc) GPIOBUS_PIN_SETFLAGS((sc)->sc_busdev, \
- (sc)->sc_dev, OW_PIN, GPIO_PIN_INPUT)
-#define GETPIN(sc, bit) GPIOBUS_PIN_GET((sc)->sc_busdev, \
- (sc)->sc_dev, OW_PIN, bit)
-#define LOW(sc) GPIOBUS_PIN_SET((sc)->sc_busdev, \
- (sc)->sc_dev, OW_PIN, GPIO_PIN_LOW)
+#define OUTPIN(sc) gpio_pin_setflags((sc)->sc_pin, GPIO_PIN_OUTPUT)
+#define INPIN(sc) gpio_pin_setflags((sc)->sc_pin, GPIO_PIN_INPUT)
+#define GETPIN(sc, bp) gpio_pin_is_active((sc)->sc_pin, (bp))
+#define LOW(sc) gpio_pin_set_active((sc)->sc_pin, false)
/*
* WRITE-ONE (see owll_if.m for timings) From Figure 4-1 AN-937
@@ -183,12 +186,8 @@ static int
owc_gpiobus_write_one(device_t dev, struct ow_timing *t)
{
struct owc_gpiobus_softc *sc;
- int error;
sc = device_get_softc(dev);
- error = GETBUS(sc);
- if (error != 0)
- return (error);
critical_enter();
@@ -203,8 +202,6 @@ owc_gpiobus_write_one(device_t dev, struct ow_timing *t)
critical_exit();
- RELBUS(sc);
-
return (0);
}
@@ -224,12 +221,8 @@ static int
owc_gpiobus_write_zero(device_t dev, struct ow_timing *t)
{
struct owc_gpiobus_softc *sc;
- int error;
sc = device_get_softc(dev);
- error = GETBUS(sc);
- if (error != 0)
- return (error);
critical_enter();
@@ -244,8 +237,6 @@ owc_gpiobus_write_zero(device_t dev, struct ow_timing *t)
critical_exit();
- RELBUS(sc);
-
return (0);
}
@@ -268,13 +259,10 @@ static int
owc_gpiobus_read_data(device_t dev, struct ow_timing *t, int *bit)
{
struct owc_gpiobus_softc *sc;
- int error, sample;
+ bool sample;
sbintime_t then, now;
sc = device_get_softc(dev);
- error = GETBUS(sc);
- if (error != 0)
- return (error);
critical_enter();
@@ -293,7 +281,7 @@ owc_gpiobus_read_data(device_t dev, struct ow_timing *t, int *bit)
do {
now = sbinuptime();
GETPIN(sc, &sample);
- } while (now - then < (t->t_rdv + 2) * SBT_1US && sample == 0);
+ } while (now - then < (t->t_rdv + 2) * SBT_1US && sample == false);
critical_exit();
if (now - then < t->t_rdv * SBT_1US)
@@ -306,9 +294,7 @@ owc_gpiobus_read_data(device_t dev, struct ow_timing *t, int *bit)
now = sbinuptime();
} while (now - then < (t->t_slot + t->t_rec) * SBT_1US);
- RELBUS(sc);
-
- return (error);
+ return (0);
}
/*
@@ -324,32 +310,31 @@ owc_gpiobus_read_data(device_t dev, struct ow_timing *t, int *bit)
* |<tPDH>|
*
* Note: for Regular Speed operations, tRSTL + tR should be less than 960us to
- * avoid interferring with other devices on the bus
+ * avoid interfering with other devices on the bus.
+ *
+ * Return values in *bit:
+ * -1 = Bus wiring error (stuck low).
+ * 0 = no presence pulse
+ * 1 = presence pulse detected
*/
static int
owc_gpiobus_reset_and_presence(device_t dev, struct ow_timing *t, int *bit)
{
struct owc_gpiobus_softc *sc;
- int error;
- int buf = -1;
+ bool sample;
sc = device_get_softc(dev);
- error = GETBUS(sc);
- if (error != 0)
- return (error);
/*
* Read the current state of the bus. The steady state of an idle bus is
* high. Badly wired buses that are missing the required pull up, or
* that have a short circuit to ground cause all kinds of mischief when
- * we try to read them later. Return EIO and release the bus if the bus
- * is currently low.
+ * we try to read them later. Return EIO if the bus is currently low.
*/
INPIN(sc);
- GETPIN(sc, &buf);
- if (buf == 0) {
+ GETPIN(sc, &sample);
+ if (sample == false) {
*bit = -1;
- RELBUS(sc);
return (EIO);
}
@@ -365,8 +350,8 @@ owc_gpiobus_reset_and_presence(device_t dev, struct ow_timing *t, int *bit)
DELAY(t->t_pdh + t->t_pdl / 2);
/* Read presence pulse */
- GETPIN(sc, &buf);
- *bit = !!buf;
+ GETPIN(sc, &sample);
+ *bit = sample;
critical_exit();
@@ -377,15 +362,12 @@ owc_gpiobus_reset_and_presence(device_t dev, struct ow_timing *t, int *bit)
* window. It should return to high. If it is low, then we have some
* problem and should abort the reset.
*/
- GETPIN(sc, &buf);
- if (buf == 0) {
+ GETPIN(sc, &sample);
+ if (sample == false) {
*bit = -1;
- RELBUS(sc);
return (EIO);
}
- RELBUS(sc);
-
return (0);
}
@@ -393,9 +375,6 @@ static devclass_t owc_gpiobus_devclass;
static device_method_t owc_gpiobus_methods[] = {
/* Device interface */
-#ifdef FDT
- DEVMETHOD(device_identify, owc_gpiobus_identify),
-#endif
DEVMETHOD(device_probe, owc_gpiobus_probe),
DEVMETHOD(device_attach, owc_gpiobus_attach),
DEVMETHOD(device_detach, owc_gpiobus_detach),
@@ -413,6 +392,10 @@ static driver_t owc_gpiobus_driver = {
sizeof(struct owc_gpiobus_softc),
};
+#ifdef FDT
+DRIVER_MODULE(owc_gpiobus, simplebus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0);
+#endif
+
DRIVER_MODULE(owc_gpiobus, gpiobus, owc_gpiobus_driver, owc_gpiobus_devclass, 0, 0);
MODULE_DEPEND(owc_gpiobus, ow, 1, 1, 1);
MODULE_DEPEND(owc_gpiobus, gpiobus, 1, 1, 1);