Home | History | Annotate | Line # | Download | only in gpio
gpioiic.c revision 1.1.2.3
      1 /* $NetBSD: gpioiic.c,v 1.1.2.3 2010/03/11 15:03:26 yamt Exp $ */
      2 /*	$OpenBSD: gpioiic.c,v 1.8 2008/11/24 12:12:12 mbalmer Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 2006 Alexander Yurchenko <grange (at) openbsd.org>
      6  *
      7  * Permission to use, copy, modify, and distribute this software for any
      8  * purpose with or without fee is hereby granted, provided that the above
      9  * copyright notice and this permission notice appear in all copies.
     10  *
     11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  */
     19 
     20 #include <sys/cdefs.h>
     21 __KERNEL_RCSID(0, "$NetBSD: gpioiic.c,v 1.1.2.3 2010/03/11 15:03:26 yamt Exp $");
     22 
     23 /*
     24  * I2C bus bit-banging through GPIO pins.
     25  */
     26 
     27 #include <sys/param.h>
     28 #include <sys/systm.h>
     29 #include <sys/device.h>
     30 #include <sys/gpio.h>
     31 #include <sys/rwlock.h>
     32 
     33 #include <dev/gpio/gpiovar.h>
     34 
     35 #include <dev/i2c/i2cvar.h>
     36 #include <dev/i2c/i2c_bitbang.h>
     37 
     38 #define GPIOIIC_PIN_SDA		0
     39 #define GPIOIIC_PIN_SCL		1
     40 #define GPIOIIC_NPINS		2
     41 
     42 #define GPIOIIC_SDA		0x01
     43 #define GPIOIIC_SCL		0x02
     44 
     45 struct gpioiic_softc {
     46 	void *			sc_gpio;
     47 	struct gpio_pinmap	sc_map;
     48 	int			_map[GPIOIIC_NPINS];
     49 
     50 	struct i2c_controller	sc_i2c_tag;
     51 	device_t		sc_i2c_dev;
     52 	krwlock_t		sc_i2c_lock;
     53 
     54 	int			sc_sda;
     55 	int			sc_scl;
     56 };
     57 
     58 int		gpioiic_match(device_t, cfdata_t, void *);
     59 void		gpioiic_attach(device_t, device_t, void *);
     60 int		gpioiic_detach(device_t, int);
     61 
     62 int		gpioiic_i2c_acquire_bus(void *, int);
     63 void		gpioiic_i2c_release_bus(void *, int);
     64 int		gpioiic_i2c_send_start(void *, int);
     65 int		gpioiic_i2c_send_stop(void *, int);
     66 int		gpioiic_i2c_initiate_xfer(void *, i2c_addr_t, int);
     67 int		gpioiic_i2c_read_byte(void *, u_int8_t *, int);
     68 int		gpioiic_i2c_write_byte(void *, u_int8_t, int);
     69 
     70 void		gpioiic_bb_set_bits(void *, u_int32_t);
     71 void		gpioiic_bb_set_dir(void *, u_int32_t);
     72 u_int32_t	gpioiic_bb_read_bits(void *);
     73 
     74 CFATTACH_DECL_NEW(gpioiic, sizeof(struct gpioiic_softc),
     75 	gpioiic_match, gpioiic_attach, gpioiic_detach, NULL);
     76 
     77 extern struct cfdriver gpioiic_cd;
     78 
     79 static const struct i2c_bitbang_ops gpioiic_bbops = {
     80 	gpioiic_bb_set_bits,
     81 	gpioiic_bb_set_dir,
     82 	gpioiic_bb_read_bits,
     83 	{ GPIOIIC_SDA, GPIOIIC_SCL, GPIOIIC_SDA, 0 }
     84 };
     85 
     86 int
     87 gpioiic_match(device_t parent, cfdata_t cf, void *aux)
     88 {
     89 	struct gpio_attach_args *ga = aux;
     90 
     91 	if (strcmp(ga->ga_dvname, cf->cf_name))
     92 		return 0;
     93 
     94 	if (ga->ga_offset == -1)
     95 		return 0;
     96 
     97 	/* Check that we have enough pins */
     98 	if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) {
     99 		aprint_debug("%s: invalid pin mask 0x%02x\n", cf->cf_name,
    100 		    ga->ga_mask);
    101 		return 0;
    102 	}
    103 	return 1;
    104 }
    105 
    106 void
    107 gpioiic_attach(struct device *parent, struct device *self, void *aux)
    108 {
    109 	struct gpioiic_softc *sc = device_private(self);
    110 	struct gpio_attach_args *ga = aux;
    111 	struct i2cbus_attach_args iba;
    112 	int caps;
    113 
    114 	/* Map pins */
    115 	sc->sc_gpio = ga->ga_gpio;
    116 	sc->sc_map.pm_map = sc->_map;
    117 	if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask,
    118 	    &sc->sc_map)) {
    119 		aprint_error(": can't map pins\n");
    120 		return;
    121 	}
    122 
    123 	/* Configure SDA pin */
    124 	caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA);
    125 	if (!(caps & GPIO_PIN_OUTPUT)) {
    126 		aprint_error(": SDA pin is unable to drive output\n");
    127 		goto fail;
    128 	}
    129 	if (!(caps & GPIO_PIN_INPUT)) {
    130 		aprint_error(": SDA pin is unable to read input\n");
    131 		goto fail;
    132 	}
    133 	aprint_normal(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]);
    134 	sc->sc_sda = GPIO_PIN_OUTPUT;
    135 	if (caps & GPIO_PIN_OPENDRAIN) {
    136 		aprint_normal(" open-drain");
    137 		sc->sc_sda |= GPIO_PIN_OPENDRAIN;
    138 	} else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) {
    139 		aprint_normal(" push-pull tri-state");
    140 		sc->sc_sda |= GPIO_PIN_PUSHPULL;
    141 	}
    142 	if (caps & GPIO_PIN_PULLUP) {
    143 		aprint_normal(" pull-up");
    144 		sc->sc_sda |= GPIO_PIN_PULLUP;
    145 	}
    146 	gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda);
    147 
    148 	/* Configure SCL pin */
    149 	caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL);
    150 	if (!(caps & GPIO_PIN_OUTPUT)) {
    151 		aprint_error(": SCL pin is unable to drive output\n");
    152 		goto fail;
    153 	}
    154 	aprint_normal(", SCL[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SCL]);
    155 	sc->sc_scl = GPIO_PIN_OUTPUT;
    156 	if (caps & GPIO_PIN_OPENDRAIN) {
    157 		aprint_normal(" open-drain");
    158 		sc->sc_scl |= GPIO_PIN_OPENDRAIN;
    159 		if (caps & GPIO_PIN_PULLUP) {
    160 			aprint_normal(" pull-up");
    161 			sc->sc_scl |= GPIO_PIN_PULLUP;
    162 		}
    163 	} else if (caps & GPIO_PIN_PUSHPULL) {
    164 		aprint_normal(" push-pull");
    165 		sc->sc_scl |= GPIO_PIN_PUSHPULL;
    166 	}
    167 	gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl);
    168 
    169 	aprint_normal("\n");
    170 
    171 	/* Attach I2C bus */
    172 	rw_init(&sc->sc_i2c_lock);
    173 	sc->sc_i2c_tag.ic_cookie = sc;
    174 	sc->sc_i2c_tag.ic_acquire_bus = gpioiic_i2c_acquire_bus;
    175 	sc->sc_i2c_tag.ic_release_bus = gpioiic_i2c_release_bus;
    176 	sc->sc_i2c_tag.ic_send_start = gpioiic_i2c_send_start;
    177 	sc->sc_i2c_tag.ic_send_stop = gpioiic_i2c_send_stop;
    178 	sc->sc_i2c_tag.ic_initiate_xfer = gpioiic_i2c_initiate_xfer;
    179 	sc->sc_i2c_tag.ic_read_byte = gpioiic_i2c_read_byte;
    180 	sc->sc_i2c_tag.ic_write_byte = gpioiic_i2c_write_byte;
    181 	sc->sc_i2c_tag.ic_exec = NULL;
    182 
    183 	memset(&iba, 0, sizeof(iba));
    184 	iba.iba_type = I2C_TYPE_SMBUS;
    185 	iba.iba_tag = &sc->sc_i2c_tag;
    186 	sc->sc_i2c_dev = config_found(self, &iba, iicbus_print);
    187 
    188 	if (!pmf_device_register(self, NULL, NULL))
    189 		aprint_error("%s: could not establish power handler\n",
    190 		    device_xname(self));
    191 	return;
    192 
    193 fail:
    194 	gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    195 }
    196 
    197 int
    198 gpioiic_detach(struct device *self, int flags)
    199 {
    200 	struct gpioiic_softc *sc = device_private(self);
    201 	int rv = 0;
    202 
    203 	if (sc->sc_i2c_dev != NULL)
    204 		rv = config_detach(sc->sc_i2c_dev, flags);
    205 
    206 	if (!rv) {
    207 		gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    208 		pmf_device_deregister(self);
    209 	}
    210 	return rv;
    211 }
    212 
    213 int
    214 gpioiic_i2c_acquire_bus(void *cookie, int flags)
    215 {
    216 	struct gpioiic_softc *sc = cookie;
    217 
    218 	if (flags & I2C_F_POLL)
    219 		return 0;
    220 
    221 	rw_enter(&sc->sc_i2c_lock, RW_WRITER);
    222 	return 1;
    223 }
    224 
    225 void
    226 gpioiic_i2c_release_bus(void *cookie, int flags)
    227 {
    228 	struct gpioiic_softc *sc = cookie;
    229 
    230 	if (flags & I2C_F_POLL)
    231 		return;
    232 
    233 	rw_exit(&sc->sc_i2c_lock);
    234 }
    235 
    236 int
    237 gpioiic_i2c_send_start(void *cookie, int flags)
    238 {
    239 	return i2c_bitbang_send_start(cookie, flags, &gpioiic_bbops);
    240 }
    241 
    242 int
    243 gpioiic_i2c_send_stop(void *cookie, int flags)
    244 {
    245 	return i2c_bitbang_send_stop(cookie, flags, &gpioiic_bbops);
    246 }
    247 
    248 int
    249 gpioiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags)
    250 {
    251 	return i2c_bitbang_initiate_xfer(cookie, addr, flags, &gpioiic_bbops);
    252 }
    253 
    254 int
    255 gpioiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags)
    256 {
    257 	return i2c_bitbang_read_byte(cookie, bytep, flags, &gpioiic_bbops);
    258 }
    259 
    260 int
    261 gpioiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags)
    262 {
    263 	return i2c_bitbang_write_byte(cookie, byte, flags, &gpioiic_bbops);
    264 }
    265 
    266 void
    267 gpioiic_bb_set_bits(void *cookie, u_int32_t bits)
    268 {
    269 	struct gpioiic_softc *sc = cookie;
    270 
    271 	gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
    272 	    bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
    273 	gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL,
    274 	    bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
    275 }
    276 
    277 void
    278 gpioiic_bb_set_dir(void *cookie, u_int32_t bits)
    279 {
    280 	struct gpioiic_softc *sc = cookie;
    281 	int sda = sc->sc_sda;
    282 
    283 	sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
    284 	sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT);
    285 	if ((sda & GPIO_PIN_PUSHPULL) && !(bits & GPIOIIC_SDA))
    286 		sda |= GPIO_PIN_TRISTATE;
    287 	if (sc->sc_sda != sda) {
    288 		sc->sc_sda = sda;
    289 		gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA,
    290 		    sc->sc_sda);
    291 	}
    292 }
    293 
    294 u_int32_t
    295 gpioiic_bb_read_bits(void *cookie)
    296 {
    297 	struct gpioiic_softc *sc = cookie;
    298 
    299 	return gpio_pin_read(sc->sc_gpio, &sc->sc_map,
    300 	    GPIOIIC_PIN_SDA) == GPIO_PIN_HIGH ? GPIOIIC_SDA : 0;
    301 }
    302