diff options
author | 2006-01-14 00:14:21 +0000 | |
---|---|---|
committer | 2006-01-14 00:14:21 +0000 | |
commit | d011abfb18df509915aecc85f95a2cb2133d85f9 (patch) | |
tree | 3c290486e46bcafffc3e98596d4f234938a22a3c | |
parent | Put back i2c bit-banging code, we'll need it soon. (diff) | |
download | wireguard-openbsd-d011abfb18df509915aecc85f95a2cb2133d85f9.tar.xz wireguard-openbsd-d011abfb18df509915aecc85f95a2cb2133d85f9.zip |
Support for I2C bus bit-banging through the GPIO pins.
Now Soekris people can enjoy our fancy I2C stuff, too:
nsclpcsio0 at isa0 port 0x2e/2: NSC PC87366 rev 9: GPIO VLM TMS
gpio1 at nsclpcsio0: 29 pins
gpioiic0 at gpio1 pins 17 19
iic0 at gpioiic0
maxds0 at iic0 addr 0x48: ds1624, starting
maxds1 at iic0 addr 0x49: ds1624, starting
-rw-r--r-- | sys/dev/gpio/files.gpio | 6 | ||||
-rw-r--r-- | sys/dev/gpio/gpioiic.c | 213 |
2 files changed, 218 insertions, 1 deletions
diff --git a/sys/dev/gpio/files.gpio b/sys/dev/gpio/files.gpio index 4a19ba656e5..1dfe1562ff2 100644 --- a/sys/dev/gpio/files.gpio +++ b/sys/dev/gpio/files.gpio @@ -1,7 +1,11 @@ -# $OpenBSD: files.gpio,v 1.3 2006/01/05 11:52:24 grange Exp $ +# $OpenBSD: files.gpio,v 1.4 2006/01/14 00:14:21 grange Exp $ define gpio {offset, mask} device gpio: gpio attach gpio at gpiobus file dev/gpio/gpio.c gpio needs-flag + +device gpioiic: i2cbus, i2c_bitbang +attach gpioiic at gpio +file dev/gpio/gpioiic.c gpioiic diff --git a/sys/dev/gpio/gpioiic.c b/sys/dev/gpio/gpioiic.c new file mode 100644 index 00000000000..a6ce1a4c783 --- /dev/null +++ b/sys/dev/gpio/gpioiic.c @@ -0,0 +1,213 @@ +/* $OpenBSD: gpioiic.c,v 1.1 2006/01/14 00:14:21 grange Exp $ */ + +/* + * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * I2C bus bit-banging through GPIO pins. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/gpio.h> + +#include <dev/gpio/gpiovar.h> + +#include <dev/i2c/i2cvar.h> +#include <dev/i2c/i2c_bitbang.h> + +#define GPIOIIC_PIN_SDA 0 +#define GPIOIIC_PIN_SCL 1 +#define GPIOIIC_NPINS 2 + +#define GPIOIIC_SDA 0x01 +#define GPIOIIC_SCL 0x02 + +struct gpioiic_softc { + struct device sc_dev; + + void * sc_gpio; + struct gpio_pinmap sc_map; + int __map[GPIOIIC_NPINS]; + + struct i2c_controller sc_i2c_tag; + struct lock sc_i2c_lock; +}; + +int gpioiic_match(struct device *, void *, void *); +void gpioiic_attach(struct device *, struct device *, void *); + +int gpioiic_i2c_acquire_bus(void *, int); +void gpioiic_i2c_release_bus(void *, int); +int gpioiic_i2c_send_start(void *, int); +int gpioiic_i2c_send_stop(void *, int); +int gpioiic_i2c_initiate_xfer(void *, i2c_addr_t, int); +int gpioiic_i2c_read_byte(void *, u_int8_t *, int); +int gpioiic_i2c_write_byte(void *, u_int8_t, int); + +void gpioiic_bb_set_bits(void *, u_int32_t); +void gpioiic_bb_set_dir(void *, u_int32_t); +u_int32_t gpioiic_bb_read_bits(void *); + +struct cfattach gpioiic_ca = { + sizeof(struct gpioiic_softc), + gpioiic_match, + gpioiic_attach +}; + +struct cfdriver gpioiic_cd = { + NULL, "gpioiic", DV_DULL +}; + +static const struct i2c_bitbang_ops gpioiic_bbops = { + gpioiic_bb_set_bits, + gpioiic_bb_set_dir, + gpioiic_bb_read_bits, + { GPIOIIC_SDA, GPIOIIC_SCL, GPIOIIC_SDA, 0 } +}; + +int +gpioiic_match(struct device *parent, void *match, void *aux) +{ + struct cfdata *cf = match; + + if (strcmp(cf->cf_driver->cd_name, "gpioiic") == 0) + return (1); + + return (0); +} + +void +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; + + if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) { + printf(": invalid pin mask\n"); + return; + } + + 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, + &sc->sc_map)) { + printf(": can't map pins\n"); + 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); + + printf("\n"); + + /* Attach I2C bus */ + lockinit(&sc->sc_i2c_lock, PRIBIO | PCATCH, "iiclk", 0, 0); + sc->sc_i2c_tag.ic_cookie = sc; + sc->sc_i2c_tag.ic_acquire_bus = gpioiic_i2c_acquire_bus; + sc->sc_i2c_tag.ic_release_bus = gpioiic_i2c_release_bus; + sc->sc_i2c_tag.ic_send_start = gpioiic_i2c_send_start; + sc->sc_i2c_tag.ic_send_stop = gpioiic_i2c_send_stop; + sc->sc_i2c_tag.ic_initiate_xfer = gpioiic_i2c_initiate_xfer; + sc->sc_i2c_tag.ic_read_byte = gpioiic_i2c_read_byte; + sc->sc_i2c_tag.ic_write_byte = gpioiic_i2c_write_byte; + + bzero(&iba, sizeof(iba)); + iba.iba_name = "iic"; + iba.iba_tag = &sc->sc_i2c_tag; + config_found(self, &iba, iicbus_print); +} + +int +gpioiic_i2c_acquire_bus(void *cookie, int flags) +{ + struct gpioiic_softc *sc = cookie; + + if (cold || (flags & I2C_F_POLL)) + return (0); + + return (lockmgr(&sc->sc_i2c_lock, LK_EXCLUSIVE, NULL)); +} + +void +gpioiic_i2c_release_bus(void *cookie, int flags) +{ + struct gpioiic_softc *sc = cookie; + + if (cold || (flags & I2C_F_POLL)) + return; + + lockmgr(&sc->sc_i2c_lock, LK_RELEASE, NULL); +} + +int +gpioiic_i2c_send_start(void *cookie, int flags) +{ + return (i2c_bitbang_send_start(cookie, flags, &gpioiic_bbops)); +} + +int +gpioiic_i2c_send_stop(void *cookie, int flags) +{ + return (i2c_bitbang_send_stop(cookie, flags, &gpioiic_bbops)); +} + +int +gpioiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) +{ + return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &gpioiic_bbops)); +} + +int +gpioiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags) +{ + return (i2c_bitbang_read_byte(cookie, bytep, flags, &gpioiic_bbops)); +} + +int +gpioiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags) +{ + return (i2c_bitbang_write_byte(cookie, byte, flags, &gpioiic_bbops)); +} + +void +gpioiic_bb_set_bits(void *cookie, u_int32_t bits) +{ + struct gpioiic_softc *sc = cookie; + + gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, + bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW); + gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, + bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW); +} + +void +gpioiic_bb_set_dir(void *cookie, u_int32_t bits) +{ +} + +u_int32_t +gpioiic_bb_read_bits(void *cookie) +{ + struct gpioiic_softc *sc = cookie; + + return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, + GPIOIIC_PIN_SDA) == GPIO_PIN_HIGH ? GPIOIIC_SDA : 0); +} |