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/gpio/gpioiic.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 /*      $OpenBSD: gpioiic.c,v 1.11 2022/04/06 18:59:28 naddy Exp $      */
    2 
    3 /*
    4  * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 /*
   20  * I2C bus bit-banging through GPIO pins.
   21  */
   22 
   23 #include <sys/param.h>
   24 #include <sys/systm.h>
   25 #include <sys/device.h>
   26 #include <sys/gpio.h>
   27 #include <sys/rwlock.h>
   28 
   29 #include <dev/gpio/gpiovar.h>
   30 
   31 #include <dev/i2c/i2cvar.h>
   32 #include <dev/i2c/i2c_bitbang.h>
   33 
   34 #define GPIOIIC_PIN_SDA         0
   35 #define GPIOIIC_PIN_SCL         1
   36 #define GPIOIIC_NPINS           2
   37 
   38 /* flags */
   39 #define GPIOIIC_PIN_REVERSE     0x01
   40 
   41 #define GPIOIIC_SDA             0x01
   42 #define GPIOIIC_SCL             0x02
   43 
   44 struct gpioiic_softc {
   45         struct device           sc_dev;
   46 
   47         void *                  sc_gpio;
   48         struct gpio_pinmap      sc_map;
   49         int                     __map[GPIOIIC_NPINS];
   50 
   51         struct i2c_controller   sc_i2c_tag;
   52         struct rwlock           sc_i2c_lock;
   53 
   54         int                     sc_pin_sda;
   55         int                     sc_pin_scl;
   56 
   57         int                     sc_sda;
   58         int                     sc_scl;
   59 };
   60 
   61 int             gpioiic_match(struct device *, void *, void *);
   62 void            gpioiic_attach(struct device *, struct device *, void *);
   63 int             gpioiic_detach(struct device *, int);
   64 
   65 int             gpioiic_i2c_acquire_bus(void *, int);
   66 void            gpioiic_i2c_release_bus(void *, int);
   67 int             gpioiic_i2c_send_start(void *, int);
   68 int             gpioiic_i2c_send_stop(void *, int);
   69 int             gpioiic_i2c_initiate_xfer(void *, i2c_addr_t, int);
   70 int             gpioiic_i2c_read_byte(void *, u_int8_t *, int);
   71 int             gpioiic_i2c_write_byte(void *, u_int8_t, int);
   72 
   73 void            gpioiic_bb_set_bits(void *, u_int32_t);
   74 void            gpioiic_bb_set_dir(void *, u_int32_t);
   75 u_int32_t       gpioiic_bb_read_bits(void *);
   76 
   77 const struct cfattach gpioiic_ca = {
   78         sizeof(struct gpioiic_softc),
   79         gpioiic_match,
   80         gpioiic_attach,
   81         gpioiic_detach
   82 };
   83 
   84 struct cfdriver gpioiic_cd = {
   85         NULL, "gpioiic", DV_DULL
   86 };
   87 
   88 static const struct i2c_bitbang_ops gpioiic_bbops = {
   89         gpioiic_bb_set_bits,
   90         gpioiic_bb_set_dir,
   91         gpioiic_bb_read_bits,
   92         { GPIOIIC_SDA, GPIOIIC_SCL, GPIOIIC_SDA, 0 }
   93 };
   94 
   95 int
   96 gpioiic_match(struct device *parent, void *match, void *aux)
   97 {
   98         struct cfdata *cf = match;
   99         struct gpio_attach_args *ga = aux;
  100 
  101         if (ga->ga_offset == -1)
  102                 return 0;
  103 
  104         return (strcmp(cf->cf_driver->cd_name, "gpioiic") == 0);
  105 }
  106 
  107 void
  108 gpioiic_attach(struct device *parent, struct device *self, void *aux)
  109 {
  110         struct gpioiic_softc *sc = (struct gpioiic_softc *)self;
  111         struct gpio_attach_args *ga = aux;
  112         struct i2cbus_attach_args iba;
  113         int caps;
  114 
  115         /* Check that we have enough pins */
  116         if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) {
  117                 printf(": invalid pin mask\n");
  118                 return;
  119         }
  120 
  121         /* Map pins */
  122         sc->sc_gpio = ga->ga_gpio;
  123         sc->sc_map.pm_map = sc->__map;
  124         if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
  125             &sc->sc_map)) {
  126                 printf(": can't map pins\n");
  127                 return;
  128         }
  129         
  130         if (ga->ga_flags & GPIOIIC_PIN_REVERSE) {
  131                 sc->sc_pin_sda = GPIOIIC_PIN_SCL;
  132                 sc->sc_pin_scl = GPIOIIC_PIN_SDA;
  133         } else {
  134                 sc->sc_pin_sda = GPIOIIC_PIN_SDA;
  135                 sc->sc_pin_scl = GPIOIIC_PIN_SCL;
  136         }
  137 
  138         /* Configure SDA pin */
  139         caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda);
  140         if (!(caps & GPIO_PIN_OUTPUT)) {
  141                 printf(": SDA pin is unable to drive output\n");
  142                 goto fail;
  143         }
  144         if (!(caps & GPIO_PIN_INPUT)) {
  145                 printf(": SDA pin is unable to read input\n");
  146                 goto fail;
  147         }
  148         printf(": SDA[%d]", sc->sc_map.pm_map[sc->sc_pin_sda]);
  149         sc->sc_sda = GPIO_PIN_OUTPUT;
  150         if (caps & GPIO_PIN_OPENDRAIN) {
  151                 printf(" open-drain");
  152                 sc->sc_sda |= GPIO_PIN_OPENDRAIN;
  153         } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) {
  154                 printf(" push-pull tri-state");
  155                 sc->sc_sda |= GPIO_PIN_PUSHPULL;
  156         }
  157         if (caps & GPIO_PIN_PULLUP) {
  158                 printf(" pull-up");
  159                 sc->sc_sda |= GPIO_PIN_PULLUP;
  160         }
  161         gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda, sc->sc_sda);
  162 
  163         /* Configure SCL pin */
  164         caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl);
  165         if (!(caps & GPIO_PIN_OUTPUT)) {
  166                 printf(": SCL pin is unable to drive output\n");
  167                 goto fail;
  168         }
  169         printf(", SCL[%d]", sc->sc_map.pm_map[sc->sc_pin_scl]);
  170         sc->sc_scl = GPIO_PIN_OUTPUT;
  171         if (caps & GPIO_PIN_OPENDRAIN) {
  172                 printf(" open-drain");
  173                 sc->sc_scl |= GPIO_PIN_OPENDRAIN;
  174                 if (caps & GPIO_PIN_PULLUP) {
  175                         printf(" pull-up");
  176                         sc->sc_scl |= GPIO_PIN_PULLUP;
  177                 }
  178         } else if (caps & GPIO_PIN_PUSHPULL) {
  179                 printf(" push-pull");
  180                 sc->sc_scl |= GPIO_PIN_PUSHPULL;
  181         }
  182         gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl, sc->sc_scl);
  183 
  184         printf("\n");
  185 
  186         /* Attach I2C bus */
  187         rw_init(&sc->sc_i2c_lock, "iiclk");
  188         sc->sc_i2c_tag.ic_cookie = sc;
  189         sc->sc_i2c_tag.ic_acquire_bus = gpioiic_i2c_acquire_bus;
  190         sc->sc_i2c_tag.ic_release_bus = gpioiic_i2c_release_bus;
  191         sc->sc_i2c_tag.ic_send_start = gpioiic_i2c_send_start;
  192         sc->sc_i2c_tag.ic_send_stop = gpioiic_i2c_send_stop;
  193         sc->sc_i2c_tag.ic_initiate_xfer = gpioiic_i2c_initiate_xfer;
  194         sc->sc_i2c_tag.ic_read_byte = gpioiic_i2c_read_byte;
  195         sc->sc_i2c_tag.ic_write_byte = gpioiic_i2c_write_byte;
  196 
  197         bzero(&iba, sizeof(iba));
  198         iba.iba_name = "iic";
  199         iba.iba_tag = &sc->sc_i2c_tag;
  200         config_found(self, &iba, iicbus_print);
  201 
  202         return;
  203 
  204 fail:
  205         gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
  206 }
  207 
  208 int
  209 gpioiic_detach(struct device *self, int flags)
  210 {
  211         return (0);
  212 }
  213 
  214 int
  215 gpioiic_i2c_acquire_bus(void *cookie, int flags)
  216 {
  217         struct gpioiic_softc *sc = cookie;
  218 
  219         if (cold || (flags & I2C_F_POLL))
  220                 return (0);
  221 
  222         return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
  223 }
  224 
  225 void
  226 gpioiic_i2c_release_bus(void *cookie, int flags)
  227 {
  228         struct gpioiic_softc *sc = cookie;
  229 
  230         if (cold || (flags & I2C_F_POLL))
  231                 return;
  232 
  233         rw_exit(&sc->sc_i2c_lock);
  234 }
  235 
  236 int
  237 gpioiic_i2c_send_start(void *cookie, int flags)
  238 {
  239         return (i2c_bitbang_send_start(cookie, flags, &gpioiic_bbops));
  240 }
  241 
  242 int
  243 gpioiic_i2c_send_stop(void *cookie, int flags)
  244 {
  245         return (i2c_bitbang_send_stop(cookie, flags, &gpioiic_bbops));
  246 }
  247 
  248 int
  249 gpioiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
  250 {
  251         return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &gpioiic_bbops));
  252 }
  253 
  254 int
  255 gpioiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags)
  256 {
  257         return (i2c_bitbang_read_byte(cookie, bytep, flags, &gpioiic_bbops));
  258 }
  259 
  260 int
  261 gpioiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags)
  262 {
  263         return (i2c_bitbang_write_byte(cookie, byte, flags, &gpioiic_bbops));
  264 }
  265 
  266 void
  267 gpioiic_bb_set_bits(void *cookie, u_int32_t bits)
  268 {
  269         struct gpioiic_softc *sc = cookie;
  270 
  271         gpio_pin_write(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda,
  272             bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
  273         gpio_pin_write(sc->sc_gpio, &sc->sc_map, sc->sc_pin_scl,
  274             bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
  275 }
  276 
  277 void
  278 gpioiic_bb_set_dir(void *cookie, u_int32_t bits)
  279 {
  280         struct gpioiic_softc *sc = cookie;
  281         int sda = sc->sc_sda;
  282 
  283         sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
  284         sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT);
  285         if ((sda & GPIO_PIN_PUSHPULL) && !(bits & GPIOIIC_SDA))
  286                 sda |= GPIO_PIN_TRISTATE;
  287         if (sc->sc_sda != sda) {
  288                 sc->sc_sda = sda;
  289                 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, sc->sc_pin_sda,
  290                     sc->sc_sda);
  291         }
  292 }
  293 
  294 u_int32_t
  295 gpioiic_bb_read_bits(void *cookie)
  296 {
  297         struct gpioiic_softc *sc = cookie;
  298         u_int32_t bits = 0;
  299 
  300         if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA) ==
  301             GPIO_PIN_HIGH)
  302                 bits |= GPIOIIC_SDA;
  303         if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL) ==
  304             GPIO_PIN_HIGH)
  305                 bits |= GPIOIIC_SCL;
  306 
  307         return bits;
  308 }

Cache object: 1793c9f6242bfc0197d6616529ab1662


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