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/p2sb/lewisburg_gpiocm.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) 2018 Stormshield
    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/param.h>
   28 #include <sys/module.h>
   29 #include <sys/systm.h>
   30 #include <sys/errno.h>
   31 #include <sys/kernel.h>
   32 #include <sys/malloc.h>
   33 #include <sys/bus.h>
   34 #include <sys/gpio.h>
   35 
   36 #include <machine/bus.h>
   37 #include <sys/rman.h>
   38 #include <machine/resource.h>
   39 
   40 #include "gpio_if.h"
   41 
   42 #include "lewisburg_gpiocm.h"
   43 #include "p2sb.h"
   44 
   45 #define PADBAR  0x00c
   46 
   47 #define PADCFG0_GPIORXDIS       (1<<9)
   48 #define PADCFG0_GPIOTXDIS       (1<<8)
   49 #define PADCFG0_GPIORXSTATE     (1<<1)
   50 #define PADCFG0_GPIOTXSTATE     (1<<0)
   51 
   52 #define MAX_PAD_PER_GROUP       24
   53 
   54 #define LBGGPIOCM_READ(sc, reg) p2sb_port_read_4(sc->p2sb, sc->port, reg)
   55 #define LBGGPIOCM_WRITE(sc, reg, val) \
   56         p2sb_port_write_4(sc->p2sb, sc->port, reg, val)
   57 #define LBGGPIOCM_LOCK(sc) p2sb_lock(sc->p2sb)
   58 #define LBGGPIOCM_UNLOCK(sc) p2sb_unlock(sc->p2sb)
   59 
   60 struct lbggroup {
   61         int groupid;
   62         int npins;
   63         int pins_off;
   64         device_t dev;
   65         char grpname;
   66 };
   67 
   68 struct lbgcommunity {
   69         uint8_t npins;
   70         const char *name;
   71         uint32_t pad_off;
   72         struct lbggroup groups[3];
   73         int ngroups;
   74         const char *grpnames;
   75 };
   76 #define LBG_COMMUNITY(n, np, g) \
   77 { \
   78         .name = n, \
   79         .npins = np, \
   80         .grpnames = g, \
   81 }
   82 
   83 static struct lbgcommunity lbg_communities[] = {
   84         LBG_COMMUNITY("LewisBurg GPIO Community 0", 72, "ABF"),
   85         LBG_COMMUNITY("LewisBurg GPIO Community 1", 61, "CDE"),
   86         LBG_COMMUNITY("LewisBurg GPIO Community 2", 0, ""),
   87         LBG_COMMUNITY("LewisBurg GPIO Community 3", 12, "I"),
   88         LBG_COMMUNITY("LewisBurg GPIO Community 4", 36, "JK"),
   89         LBG_COMMUNITY("LewisBurg GPIO Community 5", 66, "GHL"),
   90 };
   91 
   92 struct lbggpiocm_softc
   93 {
   94         int port;
   95         device_t p2sb;
   96         struct lbgcommunity *community;
   97 };
   98 
   99 static struct lbggroup *lbggpiocm_get_group(struct lbggpiocm_softc *sc,
  100     device_t child);
  101 
  102 static __inline struct lbggroup *
  103 lbggpiocm_get_group(struct lbggpiocm_softc *sc, device_t child)
  104 {
  105         int i;
  106 
  107         for (i = 0; i < sc->community->ngroups; ++i)
  108                 if (sc->community->groups[i].dev == child)
  109                         return (&sc->community->groups[i]);
  110         return (NULL);
  111 }
  112 
  113 
  114 static __inline uint32_t
  115 lbggpiocm_getpad(struct lbggpiocm_softc *sc, uint32_t pin)
  116 {
  117 
  118         if (pin >= sc->community->npins)
  119                 return (0);
  120 
  121         return (sc->community->pad_off + 2 * 4 * pin);
  122 }
  123 
  124 int
  125 lbggpiocm_get_group_npins(device_t dev, device_t child)
  126 {
  127         struct lbggpiocm_softc *sc = device_get_softc(dev);
  128         struct lbggroup *group;
  129 
  130         group = lbggpiocm_get_group(sc, child);
  131         if (group != NULL)
  132                 return (group->npins);
  133         return (-1);
  134 }
  135 
  136 char
  137 lbggpiocm_get_group_name(device_t dev, device_t child)
  138 {
  139         struct lbggpiocm_softc *sc = device_get_softc(dev);
  140         struct lbggroup *group;
  141 
  142         group = lbggpiocm_get_group(sc, child);
  143         if (group != NULL)
  144                 return (group->grpname);
  145         return ('\0');
  146 }
  147 
  148 static int
  149 lbggpiocm_pin2cpin(struct lbggpiocm_softc *sc, device_t child, uint32_t pin)
  150 {
  151         struct lbggroup *group;
  152 
  153         group = lbggpiocm_get_group(sc, child);
  154         if (group != NULL)
  155                 return (pin + group->pins_off);
  156         return (-1);
  157 }
  158 
  159 int
  160 lbggpiocm_pin_setflags(device_t dev, device_t child, uint32_t pin, uint32_t flags)
  161 {
  162         struct lbggpiocm_softc *sc = device_get_softc(dev);
  163         uint32_t padreg, padval;
  164         int rpin;
  165 
  166         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) ==
  167             (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT))
  168                 return (EINVAL);
  169 
  170         if ((flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)) == 0)
  171                 return (EINVAL);
  172 
  173         rpin = lbggpiocm_pin2cpin(sc, child, pin);
  174         if (rpin < 0)
  175                 return (EINVAL);
  176 
  177         padreg = lbggpiocm_getpad(sc, rpin);
  178 
  179         LBGGPIOCM_LOCK(sc);
  180         padval = LBGGPIOCM_READ(sc, padreg);
  181 
  182         if (flags & GPIO_PIN_INPUT) {
  183                 padval &= ~PADCFG0_GPIORXDIS;
  184                 padval |= PADCFG0_GPIOTXDIS;
  185         } else if (flags & GPIO_PIN_OUTPUT) {
  186                 padval &= ~PADCFG0_GPIOTXDIS;
  187                 padval |= PADCFG0_GPIORXDIS;
  188         }
  189 
  190         LBGGPIOCM_WRITE(sc, padreg, padval);
  191         LBGGPIOCM_UNLOCK(sc);
  192 
  193         return (0);
  194 }
  195 
  196 int
  197 lbggpiocm_pin_get(device_t dev, device_t child, uint32_t pin, uint32_t *value)
  198 {
  199         struct lbggpiocm_softc *sc = device_get_softc(dev);
  200         uint32_t padreg, val;
  201         int rpin;
  202 
  203         if (value == NULL)
  204                 return (EINVAL);
  205 
  206         rpin = lbggpiocm_pin2cpin(sc, child, pin);
  207         if (rpin < 0)
  208                 return (EINVAL);
  209 
  210         padreg = lbggpiocm_getpad(sc, rpin);
  211 
  212         LBGGPIOCM_LOCK(sc);
  213         val = LBGGPIOCM_READ(sc, padreg);
  214         LBGGPIOCM_UNLOCK(sc);
  215 
  216         if (!(val & PADCFG0_GPIOTXDIS))
  217                 *value = !!(val & PADCFG0_GPIOTXSTATE);
  218         else
  219                 *value = !!(val & PADCFG0_GPIORXSTATE);
  220 
  221         return (0);
  222 }
  223 
  224 int
  225 lbggpiocm_pin_set(device_t dev, device_t child, uint32_t pin, uint32_t value)
  226 {
  227         struct lbggpiocm_softc *sc = device_get_softc(dev);
  228         uint32_t padreg, padcfg;
  229         int rpin;
  230 
  231         rpin = lbggpiocm_pin2cpin(sc, child, pin);
  232         if (rpin < 0)
  233                 return (EINVAL);
  234 
  235         padreg = lbggpiocm_getpad(sc, rpin);
  236 
  237         LBGGPIOCM_LOCK(sc);
  238 
  239         padcfg = LBGGPIOCM_READ(sc, padreg);
  240         if (value)
  241                 padcfg |= PADCFG0_GPIOTXSTATE;
  242         else
  243                 padcfg &= ~PADCFG0_GPIOTXSTATE;
  244         LBGGPIOCM_WRITE(sc, padreg, padcfg);
  245 
  246         LBGGPIOCM_UNLOCK(sc);
  247 
  248         return (0);
  249 }
  250 
  251 int
  252 lbggpiocm_pin_toggle(device_t dev, device_t child, uint32_t pin)
  253 {
  254         struct lbggpiocm_softc *sc = device_get_softc(dev);
  255         uint32_t padreg, padcfg;
  256         int rpin;
  257 
  258         rpin = lbggpiocm_pin2cpin(sc, child, pin);
  259         if (rpin < 0)
  260                 return (EINVAL);
  261 
  262         padreg = lbggpiocm_getpad(sc, rpin);
  263 
  264         LBGGPIOCM_LOCK(sc);
  265         padcfg = LBGGPIOCM_READ(sc, padreg);
  266         padcfg ^= PADCFG0_GPIOTXSTATE;
  267         LBGGPIOCM_WRITE(sc, padreg, padcfg);
  268 
  269         LBGGPIOCM_UNLOCK(sc);
  270 
  271         return (0);
  272 }
  273 
  274 static int
  275 lbggpiocm_probe(device_t dev)
  276 {
  277         struct lbggpiocm_softc *sc = device_get_softc(dev);
  278         int unit;
  279 
  280         sc->p2sb = device_get_parent(dev);
  281         unit = device_get_unit(dev);
  282         KASSERT(unit < nitems(lbg_communities), ("Wrong number of devices or communities"));
  283         sc->port = p2sb_get_port(sc->p2sb, unit);
  284         sc->community = &lbg_communities[unit];
  285         if (sc->port < 0)
  286                 return (ENXIO);
  287 
  288         device_set_desc(dev, sc->community->name);
  289         return (BUS_PROBE_DEFAULT);
  290 }
  291 
  292 static int
  293 lbggpiocm_attach(device_t dev)
  294 {
  295         uint32_t npins;
  296         struct lbggpiocm_softc *sc;
  297         struct lbggroup *group;
  298         int i;
  299 
  300         sc = device_get_softc(dev);
  301         if (sc->community->npins == 0)
  302                 return (ENXIO);
  303 
  304         LBGGPIOCM_LOCK(sc);
  305         sc->community->pad_off = LBGGPIOCM_READ(sc, PADBAR);
  306         LBGGPIOCM_UNLOCK(sc);
  307 
  308         npins = sc->community->npins;
  309         for (i = 0; i < nitems(sc->community->groups) && npins > 0; ++i) {
  310                 group = &sc->community->groups[i];
  311 
  312                 group->groupid = i;
  313                 group->grpname = sc->community->grpnames[i];
  314                 group->pins_off = i * MAX_PAD_PER_GROUP;
  315                 group->npins = npins < MAX_PAD_PER_GROUP ? npins :
  316                         MAX_PAD_PER_GROUP;
  317                 npins -= group->npins;
  318                 group->dev = device_add_child(dev, "gpio", -1);
  319         }
  320         sc->community->ngroups = i;
  321         return (bus_generic_attach(dev));
  322 }
  323 
  324 static int
  325 lbggpiocm_detach(device_t dev)
  326 {
  327         int error;
  328 
  329         error = device_delete_children(dev);
  330         if (error)
  331                 return (error);
  332 
  333         return (bus_generic_detach(dev));
  334 }
  335 
  336 static device_method_t lbggpiocm_methods[] = {
  337         /* Device interface */
  338         DEVMETHOD(device_probe,         lbggpiocm_probe),
  339         DEVMETHOD(device_attach,        lbggpiocm_attach),
  340         DEVMETHOD(device_detach,        lbggpiocm_detach),
  341 
  342         DEVMETHOD_END
  343 };
  344 
  345 static driver_t lbggpiocm_driver = {
  346         "lbggpiocm",
  347         lbggpiocm_methods,
  348         sizeof(struct lbggpiocm_softc)
  349 };
  350 
  351 DRIVER_MODULE(lbggpiocm, p2sb, lbggpiocm_driver, NULL, NULL);

Cache object: ca88e5752827bf54dc3edf3aed270dab


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