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