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

Cache object: 9b788abd8f0f71f0d230120a7e8985e1


[ 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.