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