diff options
author | Alexander Yurchenko <grange@cvs.openbsd.org> | 2006-01-14 12:54:51 +0000 |
---|---|---|
committer | Alexander Yurchenko <grange@cvs.openbsd.org> | 2006-01-14 12:54:51 +0000 |
commit | 302aae9118e574b766cb84bfb85cb1551056f297 (patch) | |
tree | 9e93378b2192702784b8d46eb3f2c64523308bc0 /sys/dev/gpio | |
parent | 6853f9a1e6456e59edad87964e51b253a552b6bb (diff) |
Some improvements:
- use gpio_pin_caps() while configuring pins
- try to deal not only with open-drain outputs
Diffstat (limited to 'sys/dev/gpio')
-rw-r--r-- | sys/dev/gpio/gpioiic.c | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c index a6ce1a4c783..1e7fc21983a 100644 --- a/sys/dev/gpio/gpioiic.c +++ b/sys/dev/gpio/gpioiic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gpioiic.c,v 1.1 2006/01/14 00:14:21 grange Exp $ */ +/* $OpenBSD: gpioiic.c,v 1.2 2006/01/14 12:54:50 grange Exp $ */ /* * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> @@ -46,6 +46,9 @@ struct gpioiic_softc { struct i2c_controller sc_i2c_tag; struct lock sc_i2c_lock; + + int sc_sda; + int sc_scl; }; int gpioiic_match(struct device *, void *, void *); @@ -97,12 +100,15 @@ gpioiic_attach(struct device *parent, struct device *self, void *aux) struct gpioiic_softc *sc = (struct gpioiic_softc *)self; struct gpio_attach_args *ga = aux; struct i2cbus_attach_args iba; + int caps; + /* Check that we have enough pins */ if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) { printf(": invalid pin mask\n"); return; } + /* Map pins */ sc->sc_gpio = ga->ga_gpio; sc->sc_map.pm_map = sc->__map; if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, @@ -111,10 +117,44 @@ gpioiic_attach(struct device *parent, struct device *self, void *aux) return; } - gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, - GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | GPIO_PIN_PULLUP); - gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, - GPIO_PIN_OUTPUT | GPIO_PIN_OPENDRAIN | GPIO_PIN_PULLUP); + /* Configure SDA pin */ + caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA); + if (!(caps & GPIO_PIN_OUTPUT)) { + printf(": SDA pin is unable to drive output\n"); + goto fail; + } + printf(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]); + sc->sc_sda = GPIO_PIN_OUTPUT; + if (caps & GPIO_PIN_OPENDRAIN) { + printf(" open-drain"); + sc->sc_sda |= GPIO_PIN_OPENDRAIN; + if (caps & GPIO_PIN_PULLUP) { + printf(" pull-up"); + sc->sc_sda |= GPIO_PIN_PULLUP; + } + } + gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda); + + /* Configure SCL pin */ + caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL); + if (!(caps & GPIO_PIN_OUTPUT)) { + printf(": SCL pin is unable to drive output\n"); + goto fail; + } + printf(", SCL[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SCL]); + sc->sc_scl = GPIO_PIN_OUTPUT; + if (caps & GPIO_PIN_OPENDRAIN) { + printf(" open-drain"); + sc->sc_scl |= GPIO_PIN_OPENDRAIN; + if (caps & GPIO_PIN_PULLUP) { + printf(" pull-up"); + sc->sc_scl |= GPIO_PIN_PULLUP; + } + } else if (caps & GPIO_PIN_PUSHPULL) { + printf(" push-pull"); + sc->sc_scl |= GPIO_PIN_PUSHPULL; + } + gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl); printf("\n"); @@ -133,6 +173,11 @@ gpioiic_attach(struct device *parent, struct device *self, void *aux) iba.iba_name = "iic"; iba.iba_tag = &sc->sc_i2c_tag; config_found(self, &iba, iicbus_print); + + return; + +fail: + gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); } int @@ -201,6 +246,15 @@ gpioiic_bb_set_bits(void *cookie, u_int32_t bits) void gpioiic_bb_set_dir(void *cookie, u_int32_t bits) { + struct gpioiic_softc *sc = cookie; + + if (!(sc->sc_sda & GPIO_PIN_OPENDRAIN)) { + sc->sc_sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); + sc->sc_sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : + GPIO_PIN_INPUT); + gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, + sc->sc_sda); + } } u_int32_t |