[BACK]Return to gpioiic.c CVS log [TXT][DIR] Up to [local] / sys / dev / gpio

Annotation of sys/dev/gpio/gpioiic.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: gpioiic.c,v 1.7 2007/06/05 08:37:20 jsg 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: #define GPIOIIC_SDA            0x01
                     39: #define GPIOIIC_SCL            0x02
                     40:
                     41: struct gpioiic_softc {
                     42:        struct device           sc_dev;
                     43:
                     44:        void *                  sc_gpio;
                     45:        struct gpio_pinmap      sc_map;
                     46:        int                     __map[GPIOIIC_NPINS];
                     47:
                     48:        struct i2c_controller   sc_i2c_tag;
                     49:        struct rwlock           sc_i2c_lock;
                     50:
                     51:        int                     sc_sda;
                     52:        int                     sc_scl;
                     53: };
                     54:
                     55: int            gpioiic_match(struct device *, void *, void *);
                     56: void           gpioiic_attach(struct device *, struct device *, void *);
                     57: int            gpioiic_detach(struct device *, int);
                     58:
                     59: int            gpioiic_i2c_acquire_bus(void *, int);
                     60: void           gpioiic_i2c_release_bus(void *, int);
                     61: int            gpioiic_i2c_send_start(void *, int);
                     62: int            gpioiic_i2c_send_stop(void *, int);
                     63: int            gpioiic_i2c_initiate_xfer(void *, i2c_addr_t, int);
                     64: int            gpioiic_i2c_read_byte(void *, u_int8_t *, int);
                     65: int            gpioiic_i2c_write_byte(void *, u_int8_t, int);
                     66:
                     67: void           gpioiic_bb_set_bits(void *, u_int32_t);
                     68: void           gpioiic_bb_set_dir(void *, u_int32_t);
                     69: u_int32_t      gpioiic_bb_read_bits(void *);
                     70:
                     71: struct cfattach gpioiic_ca = {
                     72:        sizeof(struct gpioiic_softc),
                     73:        gpioiic_match,
                     74:        gpioiic_attach,
                     75:        gpioiic_detach
                     76: };
                     77:
                     78: struct cfdriver gpioiic_cd = {
                     79:        NULL, "gpioiic", DV_DULL
                     80: };
                     81:
                     82: static const struct i2c_bitbang_ops gpioiic_bbops = {
                     83:        gpioiic_bb_set_bits,
                     84:        gpioiic_bb_set_dir,
                     85:        gpioiic_bb_read_bits,
                     86:        { GPIOIIC_SDA, GPIOIIC_SCL, GPIOIIC_SDA, 0 }
                     87: };
                     88:
                     89: int
                     90: gpioiic_match(struct device *parent, void *match, void *aux)
                     91: {
                     92:        struct cfdata *cf = match;
                     93:
                     94:        return (strcmp(cf->cf_driver->cd_name, "gpioiic") == 0);
                     95: }
                     96:
                     97: void
                     98: gpioiic_attach(struct device *parent, struct device *self, void *aux)
                     99: {
                    100:        struct gpioiic_softc *sc = (struct gpioiic_softc *)self;
                    101:        struct gpio_attach_args *ga = aux;
                    102:        struct i2cbus_attach_args iba;
                    103:        int caps;
                    104:
                    105:        /* Check that we have enough pins */
                    106:        if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) {
                    107:                printf(": invalid pin mask\n");
                    108:                return;
                    109:        }
                    110:
                    111:        /* Map pins */
                    112:        sc->sc_gpio = ga->ga_gpio;
                    113:        sc->sc_map.pm_map = sc->__map;
                    114:        if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
                    115:            &sc->sc_map)) {
                    116:                printf(": can't map pins\n");
                    117:                return;
                    118:        }
                    119:
                    120:        /* Configure SDA pin */
                    121:        caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA);
                    122:        if (!(caps & GPIO_PIN_OUTPUT)) {
                    123:                printf(": SDA pin is unable to drive output\n");
                    124:                goto fail;
                    125:        }
                    126:        if (!(caps & GPIO_PIN_INPUT)) {
                    127:                printf(": SDA pin is unable to read input\n");
                    128:                goto fail;
                    129:        }
                    130:        printf(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]);
                    131:        sc->sc_sda = GPIO_PIN_OUTPUT;
                    132:        if (caps & GPIO_PIN_OPENDRAIN) {
                    133:                printf(" open-drain");
                    134:                sc->sc_sda |= GPIO_PIN_OPENDRAIN;
                    135:        } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) {
                    136:                printf(" push-pull tri-state");
                    137:                sc->sc_sda |= GPIO_PIN_PUSHPULL;
                    138:        }
                    139:        if (caps & GPIO_PIN_PULLUP) {
                    140:                printf(" pull-up");
                    141:                sc->sc_sda |= GPIO_PIN_PULLUP;
                    142:        }
                    143:        gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda);
                    144:
                    145:        /* Configure SCL pin */
                    146:        caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL);
                    147:        if (!(caps & GPIO_PIN_OUTPUT)) {
                    148:                printf(": SCL pin is unable to drive output\n");
                    149:                goto fail;
                    150:        }
                    151:        printf(", SCL[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SCL]);
                    152:        sc->sc_scl = GPIO_PIN_OUTPUT;
                    153:        if (caps & GPIO_PIN_OPENDRAIN) {
                    154:                printf(" open-drain");
                    155:                sc->sc_scl |= GPIO_PIN_OPENDRAIN;
                    156:                if (caps & GPIO_PIN_PULLUP) {
                    157:                        printf(" pull-up");
                    158:                        sc->sc_scl |= GPIO_PIN_PULLUP;
                    159:                }
                    160:        } else if (caps & GPIO_PIN_PUSHPULL) {
                    161:                printf(" push-pull");
                    162:                sc->sc_scl |= GPIO_PIN_PUSHPULL;
                    163:        }
                    164:        gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl);
                    165:
                    166:        printf("\n");
                    167:
                    168:        /* Attach I2C bus */
                    169:        rw_init(&sc->sc_i2c_lock, "iiclk");
                    170:        sc->sc_i2c_tag.ic_cookie = sc;
                    171:        sc->sc_i2c_tag.ic_acquire_bus = gpioiic_i2c_acquire_bus;
                    172:        sc->sc_i2c_tag.ic_release_bus = gpioiic_i2c_release_bus;
                    173:        sc->sc_i2c_tag.ic_send_start = gpioiic_i2c_send_start;
                    174:        sc->sc_i2c_tag.ic_send_stop = gpioiic_i2c_send_stop;
                    175:        sc->sc_i2c_tag.ic_initiate_xfer = gpioiic_i2c_initiate_xfer;
                    176:        sc->sc_i2c_tag.ic_read_byte = gpioiic_i2c_read_byte;
                    177:        sc->sc_i2c_tag.ic_write_byte = gpioiic_i2c_write_byte;
                    178:
                    179:        bzero(&iba, sizeof(iba));
                    180:        iba.iba_name = "iic";
                    181:        iba.iba_tag = &sc->sc_i2c_tag;
                    182:        config_found(self, &iba, iicbus_print);
                    183:
                    184:        return;
                    185:
                    186: fail:
                    187:        gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
                    188: }
                    189:
                    190: int
                    191: gpioiic_detach(struct device *self, int flags)
                    192: {
                    193:        return (0);
                    194: }
                    195:
                    196: int
                    197: gpioiic_i2c_acquire_bus(void *cookie, int flags)
                    198: {
                    199:        struct gpioiic_softc *sc = cookie;
                    200:
                    201:        if (cold || (flags & I2C_F_POLL))
                    202:                return (0);
                    203:
                    204:        return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
                    205: }
                    206:
                    207: void
                    208: gpioiic_i2c_release_bus(void *cookie, int flags)
                    209: {
                    210:        struct gpioiic_softc *sc = cookie;
                    211:
                    212:        if (cold || (flags & I2C_F_POLL))
                    213:                return;
                    214:
                    215:        rw_exit(&sc->sc_i2c_lock);
                    216: }
                    217:
                    218: int
                    219: gpioiic_i2c_send_start(void *cookie, int flags)
                    220: {
                    221:        return (i2c_bitbang_send_start(cookie, flags, &gpioiic_bbops));
                    222: }
                    223:
                    224: int
                    225: gpioiic_i2c_send_stop(void *cookie, int flags)
                    226: {
                    227:        return (i2c_bitbang_send_stop(cookie, flags, &gpioiic_bbops));
                    228: }
                    229:
                    230: int
                    231: gpioiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
                    232: {
                    233:        return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &gpioiic_bbops));
                    234: }
                    235:
                    236: int
                    237: gpioiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags)
                    238: {
                    239:        return (i2c_bitbang_read_byte(cookie, bytep, flags, &gpioiic_bbops));
                    240: }
                    241:
                    242: int
                    243: gpioiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags)
                    244: {
                    245:        return (i2c_bitbang_write_byte(cookie, byte, flags, &gpioiic_bbops));
                    246: }
                    247:
                    248: void
                    249: gpioiic_bb_set_bits(void *cookie, u_int32_t bits)
                    250: {
                    251:        struct gpioiic_softc *sc = cookie;
                    252:
                    253:        gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
                    254:            bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
                    255:        gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL,
                    256:            bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
                    257: }
                    258:
                    259: void
                    260: gpioiic_bb_set_dir(void *cookie, u_int32_t bits)
                    261: {
                    262:        struct gpioiic_softc *sc = cookie;
                    263:        int sda = sc->sc_sda;
                    264:
                    265:        sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
                    266:        sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT);
                    267:        if ((sda & GPIO_PIN_PUSHPULL) && !(bits & GPIOIIC_SDA))
                    268:                sda |= GPIO_PIN_TRISTATE;
                    269:        if (sc->sc_sda != sda) {
                    270:                sc->sc_sda = sda;
                    271:                gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
                    272:                    sc->sc_sda);
                    273:        }
                    274: }
                    275:
                    276: u_int32_t
                    277: gpioiic_bb_read_bits(void *cookie)
                    278: {
                    279:        struct gpioiic_softc *sc = cookie;
                    280:
                    281:        return (gpio_pin_read(sc->sc_gpio, &sc->sc_map,
                    282:            GPIOIIC_PIN_SDA) == GPIO_PIN_HIGH ? GPIOIIC_SDA : 0);
                    283: }

CVSweb