1 /* $OpenBSD: gpioiic.c,v 1.8 2008/11/24 12:12:12 mbalmer 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 struct gpio_attach_args *ga = aux; 94 95 if (ga->ga_offset == -1) 96 return 0; 97 98 return (strcmp(cf->cf_driver->cd_name, "gpioiic") == 0); 99 } 100 101 void 102 gpioiic_attach(struct device *parent, struct device *self, void *aux) 103 { 104 struct gpioiic_softc *sc = (struct gpioiic_softc *)self; 105 struct gpio_attach_args *ga = aux; 106 struct i2cbus_attach_args iba; 107 int caps; 108 109 /* Check that we have enough pins */ 110 if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) { 111 printf(": invalid pin mask\n"); 112 return; 113 } 114 115 /* Map pins */ 116 sc->sc_gpio = ga->ga_gpio; 117 sc->sc_map.pm_map = sc->__map; 118 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 119 &sc->sc_map)) { 120 printf(": can't map pins\n"); 121 return; 122 } 123 124 /* Configure SDA pin */ 125 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA); 126 if (!(caps & GPIO_PIN_OUTPUT)) { 127 printf(": SDA pin is unable to drive output\n"); 128 goto fail; 129 } 130 if (!(caps & GPIO_PIN_INPUT)) { 131 printf(": SDA pin is unable to read input\n"); 132 goto fail; 133 } 134 printf(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]); 135 sc->sc_sda = GPIO_PIN_OUTPUT; 136 if (caps & GPIO_PIN_OPENDRAIN) { 137 printf(" open-drain"); 138 sc->sc_sda |= GPIO_PIN_OPENDRAIN; 139 } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) { 140 printf(" push-pull tri-state"); 141 sc->sc_sda |= GPIO_PIN_PUSHPULL; 142 } 143 if (caps & GPIO_PIN_PULLUP) { 144 printf(" pull-up"); 145 sc->sc_sda |= GPIO_PIN_PULLUP; 146 } 147 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda); 148 149 /* Configure SCL pin */ 150 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL); 151 if (!(caps & GPIO_PIN_OUTPUT)) { 152 printf(": SCL pin is unable to drive output\n"); 153 goto fail; 154 } 155 printf(", SCL[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SCL]); 156 sc->sc_scl = GPIO_PIN_OUTPUT; 157 if (caps & GPIO_PIN_OPENDRAIN) { 158 printf(" open-drain"); 159 sc->sc_scl |= GPIO_PIN_OPENDRAIN; 160 if (caps & GPIO_PIN_PULLUP) { 161 printf(" pull-up"); 162 sc->sc_scl |= GPIO_PIN_PULLUP; 163 } 164 } else if (caps & GPIO_PIN_PUSHPULL) { 165 printf(" push-pull"); 166 sc->sc_scl |= GPIO_PIN_PUSHPULL; 167 } 168 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl); 169 170 printf("\n"); 171 172 /* Attach I2C bus */ 173 rw_init(&sc->sc_i2c_lock, "iiclk"); 174 sc->sc_i2c_tag.ic_cookie = sc; 175 sc->sc_i2c_tag.ic_acquire_bus = gpioiic_i2c_acquire_bus; 176 sc->sc_i2c_tag.ic_release_bus = gpioiic_i2c_release_bus; 177 sc->sc_i2c_tag.ic_send_start = gpioiic_i2c_send_start; 178 sc->sc_i2c_tag.ic_send_stop = gpioiic_i2c_send_stop; 179 sc->sc_i2c_tag.ic_initiate_xfer = gpioiic_i2c_initiate_xfer; 180 sc->sc_i2c_tag.ic_read_byte = gpioiic_i2c_read_byte; 181 sc->sc_i2c_tag.ic_write_byte = gpioiic_i2c_write_byte; 182 183 bzero(&iba, sizeof(iba)); 184 iba.iba_name = "iic"; 185 iba.iba_tag = &sc->sc_i2c_tag; 186 config_found(self, &iba, iicbus_print); 187 188 return; 189 190 fail: 191 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 192 } 193 194 int 195 gpioiic_detach(struct device *self, int flags) 196 { 197 return (0); 198 } 199 200 int 201 gpioiic_i2c_acquire_bus(void *cookie, int flags) 202 { 203 struct gpioiic_softc *sc = cookie; 204 205 if (cold || (flags & I2C_F_POLL)) 206 return (0); 207 208 return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR)); 209 } 210 211 void 212 gpioiic_i2c_release_bus(void *cookie, int flags) 213 { 214 struct gpioiic_softc *sc = cookie; 215 216 if (cold || (flags & I2C_F_POLL)) 217 return; 218 219 rw_exit(&sc->sc_i2c_lock); 220 } 221 222 int 223 gpioiic_i2c_send_start(void *cookie, int flags) 224 { 225 return (i2c_bitbang_send_start(cookie, flags, &gpioiic_bbops)); 226 } 227 228 int 229 gpioiic_i2c_send_stop(void *cookie, int flags) 230 { 231 return (i2c_bitbang_send_stop(cookie, flags, &gpioiic_bbops)); 232 } 233 234 int 235 gpioiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 236 { 237 return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &gpioiic_bbops)); 238 } 239 240 int 241 gpioiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags) 242 { 243 return (i2c_bitbang_read_byte(cookie, bytep, flags, &gpioiic_bbops)); 244 } 245 246 int 247 gpioiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags) 248 { 249 return (i2c_bitbang_write_byte(cookie, byte, flags, &gpioiic_bbops)); 250 } 251 252 void 253 gpioiic_bb_set_bits(void *cookie, u_int32_t bits) 254 { 255 struct gpioiic_softc *sc = cookie; 256 257 gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, 258 bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW); 259 gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, 260 bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW); 261 } 262 263 void 264 gpioiic_bb_set_dir(void *cookie, u_int32_t bits) 265 { 266 struct gpioiic_softc *sc = cookie; 267 int sda = sc->sc_sda; 268 269 sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 270 sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : GPIO_PIN_INPUT); 271 if ((sda & GPIO_PIN_PUSHPULL) && !(bits & GPIOIIC_SDA)) 272 sda |= GPIO_PIN_TRISTATE; 273 if (sc->sc_sda != sda) { 274 sc->sc_sda = sda; 275 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, 276 sc->sc_sda); 277 } 278 } 279 280 u_int32_t 281 gpioiic_bb_read_bits(void *cookie) 282 { 283 struct gpioiic_softc *sc = cookie; 284 285 return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, 286 GPIOIIC_PIN_SDA) == GPIO_PIN_HIGH ? GPIOIIC_SDA : 0); 287 } 288