The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ow/owc_gpiobus.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2015 M. Warner Losh <imp@FreeBSD.org>
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  */
   25 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD$");
   28 
   29 #include "opt_platform.h"
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/gpio.h>
   35 #include <sys/kernel.h>
   36 #include <sys/lock.h>
   37 #include <sys/malloc.h>
   38 #include <sys/module.h>
   39 #include <sys/mutex.h>
   40 
   41 #include <dev/gpio/gpiobusvar.h>
   42 #include <dev/ow/owll.h>
   43 
   44 #ifdef FDT
   45 #include <dev/ofw/ofw_bus.h>
   46 #include <dev/ofw/ofw_bus_subr.h>
   47 
   48 static struct ofw_compat_data compat_data[] = {
   49         {"w1-gpio",  true},
   50         {NULL,       false}
   51 };
   52 OFWBUS_PNP_INFO(compat_data);
   53 SIMPLEBUS_PNP_INFO(compat_data);
   54 #endif /* FDT */
   55 
   56 #define OW_PIN          0
   57 
   58 #define OWC_GPIOBUS_LOCK(_sc)           mtx_lock(&(_sc)->sc_mtx)
   59 #define OWC_GPIOBUS_UNLOCK(_sc)         mtx_unlock(&(_sc)->sc_mtx)
   60 #define OWC_GPIOBUS_LOCK_INIT(_sc) \
   61         mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
   62             "owc_gpiobus", MTX_DEF)
   63 #define OWC_GPIOBUS_LOCK_DESTROY(_sc)   mtx_destroy(&_sc->sc_mtx);
   64 
   65 struct owc_gpiobus_softc 
   66 {
   67         device_t        sc_dev;
   68         gpio_pin_t      sc_pin;
   69         struct mtx      sc_mtx;
   70 };
   71 
   72 static int owc_gpiobus_probe(device_t);
   73 static int owc_gpiobus_attach(device_t);
   74 static int owc_gpiobus_detach(device_t);
   75 
   76 static int
   77 owc_gpiobus_probe(device_t dev)
   78 {
   79         int rv;
   80 
   81         /*
   82          * By default we only bid to attach if specifically added by our parent
   83          * (usually via hint.owc_gpiobus.#.at=busname).  On FDT systems we bid
   84          * as the default driver based on being configured in the FDT data.
   85          */
   86         rv = BUS_PROBE_NOWILDCARD;
   87 
   88 #ifdef FDT
   89         if (ofw_bus_status_okay(dev) &&
   90             ofw_bus_search_compatible(dev, compat_data)->ocd_data)
   91                 rv = BUS_PROBE_DEFAULT;
   92 #endif
   93 
   94         device_set_desc(dev, "GPIO one-wire bus");
   95 
   96         return (rv);
   97 }
   98 
   99 static int
  100 owc_gpiobus_attach(device_t dev)
  101 {
  102         struct owc_gpiobus_softc *sc;
  103         int err;
  104 
  105         sc = device_get_softc(dev);
  106         sc->sc_dev = dev;
  107 
  108 #ifdef FDT
  109         /* Try to configure our pin from fdt data on fdt-based systems. */
  110         err = gpio_pin_get_by_ofw_idx(dev, ofw_bus_get_node(dev), OW_PIN,
  111             &sc->sc_pin);
  112 #else
  113         err = ENOENT;
  114 #endif
  115         /*
  116          * If we didn't get configured by fdt data and our parent is gpiobus,
  117          * see if we can be configured by the bus (allows hinted attachment even
  118          * on fdt-based systems).
  119          */
  120         if (err != 0 &&
  121             strcmp("gpiobus", device_get_name(device_get_parent(dev))) == 0)
  122                 err = gpio_pin_get_by_child_index(dev, OW_PIN, &sc->sc_pin);
  123 
  124         /* If we didn't get configured by either method, whine and punt. */
  125         if (err != 0) {
  126                 device_printf(sc->sc_dev,
  127                     "cannot acquire gpio pin (config error)\n");
  128                 return (err);
  129         }
  130 
  131         OWC_GPIOBUS_LOCK_INIT(sc);
  132 
  133         /*
  134          * Add the ow bus as a child, but defer probing and attaching it until
  135          * interrupts work, because we can't do IO for them until we can read
  136          * the system timecounter (which initializes after device attachments).
  137          */
  138         device_add_child(sc->sc_dev, "ow", -1);
  139         return (bus_delayed_attach_children(dev));
  140 }
  141 
  142 static int
  143 owc_gpiobus_detach(device_t dev)
  144 {
  145         struct owc_gpiobus_softc *sc;
  146         int err;
  147 
  148         sc = device_get_softc(dev);
  149 
  150         if ((err = device_delete_children(dev)) != 0)
  151                 return (err);
  152 
  153         gpio_pin_release(sc->sc_pin);
  154         OWC_GPIOBUS_LOCK_DESTROY(sc);
  155 
  156         return (0);
  157 }
  158 
  159 /*
  160  * In the diagrams below, R is driven by the resistor pullup, M is driven by the
  161  * master, and S is driven by the slave / target.
  162  */
  163 
  164 /*
  165  * These macros let what why we're doing stuff shine in the code
  166  * below, and let the how be confined to here.
  167  */
  168 #define OUTPIN(sc)      gpio_pin_setflags((sc)->sc_pin, GPIO_PIN_OUTPUT)
  169 #define INPIN(sc)       gpio_pin_setflags((sc)->sc_pin, GPIO_PIN_INPUT)
  170 #define GETPIN(sc, bp)  gpio_pin_is_active((sc)->sc_pin, (bp))
  171 #define LOW(sc)         gpio_pin_set_active((sc)->sc_pin, false)
  172 
  173 /*
  174  * WRITE-ONE (see owll_if.m for timings) From Figure 4-1 AN-937
  175  *
  176  *                     |<---------tSLOT---->|<-tREC->|
  177  *      High    RRRRM  |        RRRRRRRRRRRR|RRRRRRRRM
  178  *                   M |       R |     |  |           M
  179  *                    M|      R  |     |  |            M
  180  *      Low            MMMMMMM   |     |  |             MMMMMM...
  181  *                     |<-tLOW1->|     |  |
  182  *                     |<------15us--->|  |
  183  *                     |<--------60us---->|
  184  */
  185 static int
  186 owc_gpiobus_write_one(device_t dev, struct ow_timing *t)
  187 {
  188         struct owc_gpiobus_softc *sc;
  189 
  190         sc = device_get_softc(dev);
  191 
  192         critical_enter();
  193 
  194         /* Force low */
  195         OUTPIN(sc);
  196         LOW(sc);
  197         DELAY(t->t_low1);
  198 
  199         /* Allow resistor to float line high */
  200         INPIN(sc);
  201         DELAY(t->t_slot - t->t_low1 + t->t_rec);
  202 
  203         critical_exit();
  204 
  205         return (0);
  206 }
  207 
  208 /*
  209  * WRITE-ZERO (see owll_if.m for timings) From Figure 4-2 AN-937
  210  *
  211  *                     |<---------tSLOT------>|<-tREC->|
  212  *      High    RRRRM  |                    | |RRRRRRRM
  213  *                   M |                    | R        M
  214  *                    M|         |     |    |R          M
  215  *      Low            MMMMMMMMMMMMMMMMMMMMMR            MMMMMM...
  216  *                     |<--15us->|     |    |
  217  *                     |<------60us--->|    |
  218  *                     |<-------tLOW0------>|
  219  */
  220 static int
  221 owc_gpiobus_write_zero(device_t dev, struct ow_timing *t)
  222 {
  223         struct owc_gpiobus_softc *sc;
  224 
  225         sc = device_get_softc(dev);
  226 
  227         critical_enter();
  228 
  229         /* Force low */
  230         OUTPIN(sc);
  231         LOW(sc);
  232         DELAY(t->t_low0);
  233 
  234         /* Allow resistor to float line high */
  235         INPIN(sc);
  236         DELAY(t->t_slot - t->t_low0 + t->t_rec);
  237 
  238         critical_exit();
  239 
  240         return (0);
  241 }
  242 
  243 /*
  244  * READ-DATA (see owll_if.m for timings) From Figure 4-3 AN-937
  245  *
  246  *                     |<---------tSLOT------>|<-tREC->|
  247  *      High    RRRRM  |        rrrrrrrrrrrrrrrRRRRRRRM
  248  *                   M |       r            | R        M
  249  *                    M|      r         |   |R          M
  250  *      Low            MMMMMMMSSSSSSSSSSSSSSR            MMMMMM...
  251  *                     |<tLOWR>< sample >   |
  252  *                     |<------tRDV---->|   |
  253  *                                    ->|   |<-tRELEASE
  254  *
  255  * r -- allowed to pull high via the resitor when slave writes a 1-bit
  256  *
  257  */
  258 static int
  259 owc_gpiobus_read_data(device_t dev, struct ow_timing *t, int *bit)
  260 {
  261         struct owc_gpiobus_softc *sc;
  262         bool sample;
  263         sbintime_t then, now;
  264 
  265         sc = device_get_softc(dev);
  266 
  267         critical_enter();
  268 
  269         /* Force low for t_lowr microseconds */
  270         then = sbinuptime();
  271         OUTPIN(sc);
  272         LOW(sc);
  273         DELAY(t->t_lowr);
  274 
  275         /*
  276          * Slave is supposed to hold the line low for t_rdv microseconds for 0
  277          * and immediately float it high for a 1. This is measured from the
  278          * master's pushing the line low.
  279          */
  280         INPIN(sc);
  281         do {
  282                 now = sbinuptime();
  283                 GETPIN(sc, &sample);
  284         } while (now - then < (t->t_rdv + 2) * SBT_1US && sample == false);
  285         critical_exit();
  286 
  287         if (now - then < t->t_rdv * SBT_1US)
  288                 *bit = 1;
  289         else
  290                 *bit = 0;
  291 
  292         /* Wait out the rest of t_slot */
  293         do {
  294                 now = sbinuptime();
  295         } while (now - then < (t->t_slot + t->t_rec) * SBT_1US);
  296 
  297         return (0);
  298 }
  299 
  300 /*
  301  * RESET AND PRESENCE PULSE (see owll_if.m for timings) From Figure 4-4 AN-937
  302  *
  303  *                                  |<---------tRSTH------------>|
  304  *      High RRRM  |              | RRRRRRRS           |  RRRR RRM
  305  *               M |              |R|      |S          | R        M
  306  *                M|              R |      | S         |R          M
  307  *      Low        MMMMMMMM MMMMMM| |      |  SSSSSSSSSS            MMMMMM
  308  *                 |<----tRSTL--->| |      |<-tPDL---->|
  309  *                 |            ->| |<-tR  |           |
  310  *                                  |<tPDH>|
  311  *
  312  * Note: for Regular Speed operations, tRSTL + tR should be less than 960us to
  313  * avoid interfering with other devices on the bus.
  314  *
  315  * Return values in *bit:
  316  *  -1 = Bus wiring error (stuck low).
  317  *   0 = no presence pulse
  318  *   1 = presence pulse detected
  319  */
  320 static int
  321 owc_gpiobus_reset_and_presence(device_t dev, struct ow_timing *t, int *bit)
  322 {
  323         struct owc_gpiobus_softc *sc;
  324         bool sample;
  325 
  326         sc = device_get_softc(dev);
  327 
  328         /*
  329          * Read the current state of the bus. The steady state of an idle bus is
  330          * high. Badly wired buses that are missing the required pull up, or
  331          * that have a short circuit to ground cause all kinds of mischief when
  332          * we try to read them later. Return EIO if the bus is currently low.
  333          */
  334         INPIN(sc);
  335         GETPIN(sc, &sample);
  336         if (sample == false) {
  337                 *bit = -1;
  338                 return (EIO);
  339         }
  340 
  341         critical_enter();
  342 
  343         /* Force low */
  344         OUTPIN(sc);
  345         LOW(sc);
  346         DELAY(t->t_rstl);
  347 
  348         /* Allow resistor to float line high and then wait for reset pulse */
  349         INPIN(sc);
  350         DELAY(t->t_pdh + t->t_pdl / 2);
  351 
  352         /* Read presence pulse  */
  353         GETPIN(sc, &sample);
  354         *bit = sample;
  355 
  356         critical_exit();
  357 
  358         DELAY(t->t_rsth - (t->t_pdh + t->t_pdl / 2));   /* Timing not critical for this one */
  359 
  360         /*
  361          * Read the state of the bus after we've waited past the end of the rest
  362          * window. It should return to high. If it is low, then we have some
  363          * problem and should abort the reset.
  364          */
  365         GETPIN(sc, &sample);
  366         if (sample == false) {
  367                 *bit = -1;
  368                 return (EIO);
  369         }
  370 
  371         return (0);
  372 }
  373 
  374 static device_method_t owc_gpiobus_methods[] = {
  375         /* Device interface */
  376         DEVMETHOD(device_probe,         owc_gpiobus_probe),
  377         DEVMETHOD(device_attach,        owc_gpiobus_attach),
  378         DEVMETHOD(device_detach,        owc_gpiobus_detach),
  379 
  380         DEVMETHOD(owll_write_one,       owc_gpiobus_write_one),
  381         DEVMETHOD(owll_write_zero,      owc_gpiobus_write_zero),
  382         DEVMETHOD(owll_read_data,       owc_gpiobus_read_data),
  383         DEVMETHOD(owll_reset_and_presence,      owc_gpiobus_reset_and_presence),
  384         { 0, 0 }
  385 };
  386 
  387 static driver_t owc_gpiobus_driver = {
  388         "owc",
  389         owc_gpiobus_methods,
  390         sizeof(struct owc_gpiobus_softc),
  391 };
  392 
  393 #ifdef FDT
  394 DRIVER_MODULE(owc_gpiobus, simplebus, owc_gpiobus_driver, 0, 0);
  395 #endif
  396 
  397 DRIVER_MODULE(owc_gpiobus, gpiobus, owc_gpiobus_driver, 0, 0);
  398 MODULE_DEPEND(owc_gpiobus, ow, 1, 1, 1);
  399 MODULE_DEPEND(owc_gpiobus, gpiobus, 1, 1, 1);
  400 MODULE_VERSION(owc_gpiobus, 1);

Cache object: 3386653c4ded11a1bc3cc1e1b916f8c4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.