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/arm/xscale/ixp425/cambria_gpio.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) 2010, Andrew Thompson <thompsa@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 unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 /*
   29  * GPIO driver for Gateworks Cambria
   30  *
   31  * Note:
   32  * The Cambria PLD does not set the i2c ack bit after each write, if we used the
   33  * regular iicbus interface it would abort the xfer after the address byte
   34  * times out and not write our latch. To get around this we grab the iicbus and
   35  * then do our own bit banging. This is a compromise to changing all the iicbb
   36  * device methods to allow a flag to be passed down and is similir to how Linux
   37  * does it.
   38  *
   39  */
   40 
   41 #include <sys/cdefs.h>
   42 __FBSDID("$FreeBSD: releng/11.0/sys/arm/xscale/ixp425/cambria_gpio.c 299069 2016-05-04 15:48:59Z pfg $");
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/bus.h>
   47 
   48 #include <sys/kernel.h>
   49 #include <sys/module.h>
   50 #include <sys/rman.h>
   51 #include <sys/lock.h>
   52 #include <sys/mutex.h>
   53 #include <sys/gpio.h>
   54 
   55 #include <arm/xscale/ixp425/ixp425reg.h>
   56 #include <arm/xscale/ixp425/ixp425var.h>
   57 #include <arm/xscale/ixp425/ixdp425reg.h>
   58 
   59 #include <dev/gpio/gpiobusvar.h>
   60 #include <dev/iicbus/iiconf.h>
   61 #include <dev/iicbus/iicbus.h>
   62 
   63 #include "iicbb_if.h"
   64 #include "gpio_if.h"
   65 
   66 #define IIC_M_WR        0       /* write operation */
   67 #define PLD_ADDR        0xac    /* slave address */
   68 
   69 #define I2C_DELAY       10
   70 
   71 #define GPIO_CONF_CLR(sc, reg, mask)    \
   72         GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) &~ (mask))
   73 #define GPIO_CONF_SET(sc, reg, mask)    \
   74         GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) | (mask))
   75 
   76 #define GPIO_LOCK(_sc)          mtx_lock(&(_sc)->sc_mtx)
   77 #define GPIO_UNLOCK(_sc)        mtx_unlock(&(_sc)->sc_mtx)
   78 #define GPIO_LOCK_ASSERT(_sc)   mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
   79 
   80 #define GPIO_PINS               5
   81 struct cambria_gpio_softc {
   82         device_t                sc_dev;
   83         device_t                sc_busdev;
   84         bus_space_tag_t         sc_iot;
   85         bus_space_handle_t      sc_gpio_ioh;
   86         struct mtx              sc_mtx;
   87         struct gpio_pin         sc_pins[GPIO_PINS];
   88         uint8_t                 sc_latch;
   89         uint8_t                 sc_val;
   90 };
   91 
   92 struct cambria_gpio_pin {
   93         const char *name;
   94         int pin;
   95         int flags;
   96 };
   97 
   98 extern struct ixp425_softc *ixp425_softc;
   99 
  100 static struct cambria_gpio_pin cambria_gpio_pins[GPIO_PINS] = {
  101         { "PLD0", 0, GPIO_PIN_OUTPUT },
  102         { "PLD1", 1, GPIO_PIN_OUTPUT },
  103         { "PLD2", 2, GPIO_PIN_OUTPUT },
  104         { "PLD3", 3, GPIO_PIN_OUTPUT },
  105         { "PLD4", 4, GPIO_PIN_OUTPUT },
  106 };
  107 
  108 /*
  109  * Helpers
  110  */
  111 static int cambria_gpio_read(struct cambria_gpio_softc *, uint32_t, unsigned int *);
  112 static int cambria_gpio_write(struct cambria_gpio_softc *);
  113 
  114 /*
  115  * Driver stuff
  116  */
  117 static int cambria_gpio_probe(device_t dev);
  118 static int cambria_gpio_attach(device_t dev);
  119 static int cambria_gpio_detach(device_t dev);
  120 
  121 /*
  122  * GPIO interface
  123  */
  124 static device_t cambria_gpio_get_bus(device_t);
  125 static int cambria_gpio_pin_max(device_t dev, int *maxpin);
  126 static int cambria_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps);
  127 static int cambria_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t
  128     *flags);
  129 static int cambria_gpio_pin_getname(device_t dev, uint32_t pin, char *name);
  130 static int cambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags);
  131 static int cambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value);
  132 static int cambria_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val);
  133 static int cambria_gpio_pin_toggle(device_t dev, uint32_t pin);
  134 
  135 static int
  136 i2c_getsda(struct cambria_gpio_softc *sc)
  137 {
  138         uint32_t reg;
  139 
  140         IXP4XX_GPIO_LOCK();
  141         GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
  142 
  143         reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR);
  144         IXP4XX_GPIO_UNLOCK();
  145         return (reg & GPIO_I2C_SDA_BIT);
  146 }
  147 
  148 static void
  149 i2c_setsda(struct cambria_gpio_softc *sc, int val)
  150 {
  151 
  152         IXP4XX_GPIO_LOCK();
  153         GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SDA_BIT);
  154         if (val)
  155                 GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
  156         else
  157                 GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT);
  158         IXP4XX_GPIO_UNLOCK();
  159         DELAY(I2C_DELAY);
  160 }
  161 
  162 static void
  163 i2c_setscl(struct cambria_gpio_softc *sc, int val)
  164 {
  165 
  166         IXP4XX_GPIO_LOCK();
  167         GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SCL_BIT);
  168         if (val)
  169                 GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
  170         else
  171                 GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT);
  172         IXP4XX_GPIO_UNLOCK();
  173         DELAY(I2C_DELAY);
  174 }
  175 
  176 static void
  177 i2c_sendstart(struct cambria_gpio_softc *sc)
  178 {
  179         i2c_setsda(sc, 1);
  180         i2c_setscl(sc, 1);
  181         i2c_setsda(sc, 0);
  182         i2c_setscl(sc, 0);
  183 }
  184 
  185 static void
  186 i2c_sendstop(struct cambria_gpio_softc *sc)
  187 {
  188         i2c_setscl(sc, 1);
  189         i2c_setsda(sc, 1);
  190         i2c_setscl(sc, 0);
  191         i2c_setsda(sc, 0);
  192 }
  193 
  194 static void
  195 i2c_sendbyte(struct cambria_gpio_softc *sc, u_char data)
  196 {
  197         int i;
  198 
  199         for (i=7; i>=0; i--) {
  200                 i2c_setsda(sc, data & (1<<i));
  201                 i2c_setscl(sc, 1);
  202                 i2c_setscl(sc, 0);
  203         }
  204         i2c_setscl(sc, 1);
  205         i2c_getsda(sc);
  206         i2c_setscl(sc, 0);
  207 }
  208 
  209 static u_char
  210 i2c_readbyte(struct cambria_gpio_softc *sc)
  211 {
  212         int i;
  213         unsigned char data=0;
  214 
  215         for (i=7; i>=0; i--)
  216         {
  217                 i2c_setscl(sc, 1);
  218                 if (i2c_getsda(sc))
  219                         data |= (1<<i);
  220                 i2c_setscl(sc, 0);
  221         }
  222         return data;
  223 }
  224 
  225 static int
  226 cambria_gpio_read(struct cambria_gpio_softc *sc, uint32_t pin, unsigned int *val)
  227 {
  228         device_t dev = sc->sc_dev;
  229         int error;
  230 
  231         error = iicbus_request_bus(device_get_parent(dev), dev,
  232             IIC_DONTWAIT);
  233         if (error)
  234                 return (error);
  235 
  236         i2c_sendstart(sc);
  237         i2c_sendbyte(sc, PLD_ADDR | LSB);
  238         *val = (i2c_readbyte(sc) & (1 << pin)) != 0;
  239         i2c_sendstop(sc);
  240 
  241         iicbus_release_bus(device_get_parent(dev), dev);
  242 
  243         return (0);
  244 }
  245 
  246 static int
  247 cambria_gpio_write(struct cambria_gpio_softc *sc)
  248 {
  249         device_t dev = sc->sc_dev;
  250         int error;
  251 
  252         error = iicbus_request_bus(device_get_parent(dev), dev,
  253             IIC_DONTWAIT);
  254         if (error)
  255                 return (error);
  256 
  257         i2c_sendstart(sc);
  258         i2c_sendbyte(sc, PLD_ADDR & ~LSB);
  259         i2c_sendbyte(sc, sc->sc_latch);
  260         i2c_sendstop(sc);
  261 
  262         iicbus_release_bus(device_get_parent(dev), dev);
  263 
  264         return (0);
  265 }
  266 
  267 static device_t
  268 cambria_gpio_get_bus(device_t dev)
  269 {
  270         struct cambria_gpio_softc *sc;
  271 
  272         sc = device_get_softc(dev);
  273 
  274         return (sc->sc_busdev);
  275 }
  276 
  277 static int
  278 cambria_gpio_pin_max(device_t dev, int *maxpin)
  279 {
  280 
  281         *maxpin = GPIO_PINS - 1;
  282         return (0);
  283 }
  284 
  285 static int
  286 cambria_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
  287 {
  288         struct cambria_gpio_softc *sc = device_get_softc(dev);
  289 
  290         if (pin >= GPIO_PINS)
  291                 return (EINVAL);
  292 
  293         *caps = sc->sc_pins[pin].gp_caps;
  294         return (0);
  295 }
  296 
  297 static int
  298 cambria_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
  299 {
  300         struct cambria_gpio_softc *sc = device_get_softc(dev);
  301 
  302         if (pin >= GPIO_PINS)
  303                 return (EINVAL);
  304 
  305         *flags = sc->sc_pins[pin].gp_flags;
  306         return (0);
  307 }
  308 
  309 static int
  310 cambria_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
  311 {
  312         struct cambria_gpio_softc *sc = device_get_softc(dev);
  313 
  314         if (pin >= GPIO_PINS)
  315                 return (EINVAL);
  316 
  317         memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME);
  318         return (0);
  319 }
  320 
  321 static int
  322 cambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
  323 {
  324         struct cambria_gpio_softc *sc = device_get_softc(dev);
  325         int error;
  326         uint8_t mask;
  327 
  328         mask = 1 << pin;
  329 
  330         if (pin >= GPIO_PINS)
  331                 return (EINVAL);
  332 
  333         GPIO_LOCK(sc);
  334         sc->sc_pins[pin].gp_flags = flags;
  335 
  336         /*
  337          * Writing a logical one sets the signal high and writing a logical
  338          * zero sets the signal low. To configure a digital I/O signal as an
  339          * input, a logical one must first be written to the data bit to
  340          * three-state the associated output.
  341          */
  342         if (flags & GPIO_PIN_INPUT || sc->sc_val & mask)
  343                 sc->sc_latch |= mask; /* input or output & high */
  344         else
  345                 sc->sc_latch &= ~mask;
  346         error = cambria_gpio_write(sc);
  347         GPIO_UNLOCK(sc);
  348 
  349         return (error);
  350 }
  351 
  352 static int
  353 cambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
  354 {
  355         struct cambria_gpio_softc *sc = device_get_softc(dev);
  356         int error;
  357         uint8_t mask;
  358 
  359         mask = 1 << pin;
  360 
  361         if (pin >= GPIO_PINS)
  362                 return (EINVAL);
  363         GPIO_LOCK(sc);
  364         if (value)
  365                 sc->sc_val |= mask;
  366         else
  367                 sc->sc_val &= ~mask;
  368 
  369         if (sc->sc_pins[pin].gp_flags != GPIO_PIN_OUTPUT) {
  370                 /* just save, altering the latch will disable input */
  371                 GPIO_UNLOCK(sc);
  372                 return (0);
  373         }
  374 
  375         if (value)
  376                 sc->sc_latch |= mask;
  377         else
  378                 sc->sc_latch &= ~mask;
  379         error = cambria_gpio_write(sc);
  380         GPIO_UNLOCK(sc);
  381 
  382         return (error);
  383 }
  384 
  385 static int
  386 cambria_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val)
  387 {
  388         struct cambria_gpio_softc *sc = device_get_softc(dev);
  389         int error = 0;
  390 
  391         if (pin >= GPIO_PINS)
  392                 return (EINVAL);
  393 
  394         GPIO_LOCK(sc);
  395         if (sc->sc_pins[pin].gp_flags == GPIO_PIN_OUTPUT)
  396                 *val = (sc->sc_latch & (1 << pin)) ? 1 : 0;
  397         else
  398                 error = cambria_gpio_read(sc, pin, val);
  399         GPIO_UNLOCK(sc);
  400 
  401         return (error);
  402 }
  403 
  404 static int
  405 cambria_gpio_pin_toggle(device_t dev, uint32_t pin)
  406 {
  407         struct cambria_gpio_softc *sc = device_get_softc(dev);
  408         int error = 0;
  409 
  410         if (pin >= GPIO_PINS)
  411                 return (EINVAL);
  412 
  413         GPIO_LOCK(sc);
  414         sc->sc_val ^= (1 << pin);
  415         if (sc->sc_pins[pin].gp_flags == GPIO_PIN_OUTPUT) {
  416                 sc->sc_latch ^= (1 << pin);
  417                 error = cambria_gpio_write(sc);
  418         }
  419         GPIO_UNLOCK(sc);
  420 
  421         return (error);
  422 }
  423 
  424 static int
  425 cambria_gpio_probe(device_t dev)
  426 {
  427 
  428         device_set_desc(dev, "Gateworks Cambria GPIO driver");
  429         return (0);
  430 }
  431 
  432 static int
  433 cambria_gpio_attach(device_t dev)
  434 {
  435         struct cambria_gpio_softc *sc = device_get_softc(dev);
  436         int pin;
  437 
  438         sc->sc_dev = dev;
  439         sc->sc_iot = ixp425_softc->sc_iot;
  440         sc->sc_gpio_ioh = ixp425_softc->sc_gpio_ioh;
  441 
  442         mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  443 
  444         for (pin = 0; pin < GPIO_PINS; pin++) {
  445                 struct cambria_gpio_pin *p = &cambria_gpio_pins[pin];
  446 
  447                 strncpy(sc->sc_pins[pin].gp_name, p->name, GPIOMAXNAME);
  448                 sc->sc_pins[pin].gp_pin = pin;
  449                 sc->sc_pins[pin].gp_caps = GPIO_PIN_INPUT|GPIO_PIN_OUTPUT;
  450                 sc->sc_pins[pin].gp_flags = 0;
  451                 cambria_gpio_pin_setflags(dev, pin, p->flags);
  452         }
  453 
  454         sc->sc_busdev = gpiobus_attach_bus(dev);
  455         if (sc->sc_busdev == NULL) {
  456                 mtx_destroy(&sc->sc_mtx);
  457                 return (ENXIO);
  458         }
  459 
  460         return (0);
  461 }
  462 
  463 static int
  464 cambria_gpio_detach(device_t dev)
  465 {
  466         struct cambria_gpio_softc *sc = device_get_softc(dev);
  467 
  468         KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized"));
  469 
  470         gpiobus_detach_bus(dev);
  471         mtx_destroy(&sc->sc_mtx);
  472 
  473         return(0);
  474 }
  475 
  476 static device_method_t cambria_gpio_methods[] = {
  477         DEVMETHOD(device_probe, cambria_gpio_probe),
  478         DEVMETHOD(device_attach, cambria_gpio_attach),
  479         DEVMETHOD(device_detach, cambria_gpio_detach),
  480 
  481         /* GPIO protocol */
  482         DEVMETHOD(gpio_get_bus, cambria_gpio_get_bus),
  483         DEVMETHOD(gpio_pin_max, cambria_gpio_pin_max),
  484         DEVMETHOD(gpio_pin_getname, cambria_gpio_pin_getname),
  485         DEVMETHOD(gpio_pin_getflags, cambria_gpio_pin_getflags),
  486         DEVMETHOD(gpio_pin_getcaps, cambria_gpio_pin_getcaps),
  487         DEVMETHOD(gpio_pin_setflags, cambria_gpio_pin_setflags),
  488         DEVMETHOD(gpio_pin_get, cambria_gpio_pin_get),
  489         DEVMETHOD(gpio_pin_set, cambria_gpio_pin_set),
  490         DEVMETHOD(gpio_pin_toggle, cambria_gpio_pin_toggle),
  491         {0, 0},
  492 };
  493 
  494 static driver_t cambria_gpio_driver = {
  495         "gpio",
  496         cambria_gpio_methods,
  497         sizeof(struct cambria_gpio_softc),
  498 };
  499 static devclass_t cambria_gpio_devclass;
  500 
  501 DRIVER_MODULE(gpio_cambria, iicbus, cambria_gpio_driver, cambria_gpio_devclass, 0, 0);
  502 MODULE_VERSION(gpio_cambria, 1);
  503 MODULE_DEPEND(gpio_cambria, iicbus, 1, 1, 1);

Cache object: d1ec7d0010714d4f4afbc179b483ef2d


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