1 /* $OpenBSD: gpioiic.c,v 1.5 2006/01/18 21:47:08 grange 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 28 #include <dev/gpio/gpiovar.h> 29 30 #include <dev/i2c/i2cvar.h> 31 #include <dev/i2c/i2c_bitbang.h> 32 33 #define GPIOIIC_PIN_SDA 0 34 #define GPIOIIC_PIN_SCL 1 35 #define GPIOIIC_NPINS 2 36 37 #define GPIOIIC_SDA 0x01 38 #define GPIOIIC_SCL 0x02 39 40 struct gpioiic_softc { 41 struct device sc_dev; 42 43 void * sc_gpio; 44 struct gpio_pinmap sc_map; 45 int __map[GPIOIIC_NPINS]; 46 47 struct i2c_controller sc_i2c_tag; 48 struct lock sc_i2c_lock; 49 50 int sc_sda; 51 int sc_scl; 52 }; 53 54 int gpioiic_match(struct device *, void *, void *); 55 void gpioiic_attach(struct device *, struct device *, void *); 56 int gpioiic_detach(struct device *, int); 57 58 int gpioiic_i2c_acquire_bus(void *, int); 59 void gpioiic_i2c_release_bus(void *, int); 60 int gpioiic_i2c_send_start(void *, int); 61 int gpioiic_i2c_send_stop(void *, int); 62 int gpioiic_i2c_initiate_xfer(void *, i2c_addr_t, int); 63 int gpioiic_i2c_read_byte(void *, u_int8_t *, int); 64 int gpioiic_i2c_write_byte(void *, u_int8_t, int); 65 66 void gpioiic_bb_set_bits(void *, u_int32_t); 67 void gpioiic_bb_set_dir(void *, u_int32_t); 68 u_int32_t gpioiic_bb_read_bits(void *); 69 70 struct cfattach gpioiic_ca = { 71 sizeof(struct gpioiic_softc), 72 gpioiic_match, 73 gpioiic_attach, 74 gpioiic_detach 75 }; 76 77 struct cfdriver gpioiic_cd = { 78 NULL, "gpioiic", DV_DULL 79 }; 80 81 static const struct i2c_bitbang_ops gpioiic_bbops = { 82 gpioiic_bb_set_bits, 83 gpioiic_bb_set_dir, 84 gpioiic_bb_read_bits, 85 { GPIOIIC_SDA, GPIOIIC_SCL, GPIOIIC_SDA, 0 } 86 }; 87 88 int 89 gpioiic_match(struct device *parent, void *match, void *aux) 90 { 91 struct cfdata *cf = match; 92 93 return (strcmp(cf->cf_driver->cd_name, "gpioiic") == 0); 94 } 95 96 void 97 gpioiic_attach(struct device *parent, struct device *self, void *aux) 98 { 99 struct gpioiic_softc *sc = (struct gpioiic_softc *)self; 100 struct gpio_attach_args *ga = aux; 101 struct i2cbus_attach_args iba; 102 int caps; 103 104 /* Check that we have enough pins */ 105 if (gpio_npins(ga->ga_mask) != GPIOIIC_NPINS) { 106 printf(": invalid pin mask\n"); 107 return; 108 } 109 110 /* Map pins */ 111 sc->sc_gpio = ga->ga_gpio; 112 sc->sc_map.pm_map = sc->__map; 113 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 114 &sc->sc_map)) { 115 printf(": can't map pins\n"); 116 return; 117 } 118 119 /* Configure SDA pin */ 120 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA); 121 if (!(caps & GPIO_PIN_OUTPUT)) { 122 printf(": SDA pin is unable to drive output\n"); 123 goto fail; 124 } 125 if (!(caps & GPIO_PIN_INPUT)) { 126 printf(": SDA pin is unable to read input\n"); 127 goto fail; 128 } 129 printf(": SDA[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SDA]); 130 sc->sc_sda = GPIO_PIN_OUTPUT; 131 if (caps & GPIO_PIN_OPENDRAIN) { 132 printf(" open-drain"); 133 sc->sc_sda |= GPIO_PIN_OPENDRAIN; 134 if (caps & GPIO_PIN_PULLUP) { 135 printf(" pull-up"); 136 sc->sc_sda |= GPIO_PIN_PULLUP; 137 } 138 } 139 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, sc->sc_sda); 140 141 /* Configure SCL pin */ 142 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL); 143 if (!(caps & GPIO_PIN_OUTPUT)) { 144 printf(": SCL pin is unable to drive output\n"); 145 goto fail; 146 } 147 printf(", SCL[%d]", sc->sc_map.pm_map[GPIOIIC_PIN_SCL]); 148 sc->sc_scl = GPIO_PIN_OUTPUT; 149 if (caps & GPIO_PIN_OPENDRAIN) { 150 printf(" open-drain"); 151 sc->sc_scl |= GPIO_PIN_OPENDRAIN; 152 if (caps & GPIO_PIN_PULLUP) { 153 printf(" pull-up"); 154 sc->sc_scl |= GPIO_PIN_PULLUP; 155 } 156 } else if (caps & GPIO_PIN_PUSHPULL) { 157 printf(" push-pull"); 158 sc->sc_scl |= GPIO_PIN_PUSHPULL; 159 } 160 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, sc->sc_scl); 161 162 printf("\n"); 163 164 /* Attach I2C bus */ 165 lockinit(&sc->sc_i2c_lock, PRIBIO | PCATCH, "iiclk", 0, 0); 166 sc->sc_i2c_tag.ic_cookie = sc; 167 sc->sc_i2c_tag.ic_acquire_bus = gpioiic_i2c_acquire_bus; 168 sc->sc_i2c_tag.ic_release_bus = gpioiic_i2c_release_bus; 169 sc->sc_i2c_tag.ic_send_start = gpioiic_i2c_send_start; 170 sc->sc_i2c_tag.ic_send_stop = gpioiic_i2c_send_stop; 171 sc->sc_i2c_tag.ic_initiate_xfer = gpioiic_i2c_initiate_xfer; 172 sc->sc_i2c_tag.ic_read_byte = gpioiic_i2c_read_byte; 173 sc->sc_i2c_tag.ic_write_byte = gpioiic_i2c_write_byte; 174 175 bzero(&iba, sizeof(iba)); 176 iba.iba_name = "iic"; 177 iba.iba_tag = &sc->sc_i2c_tag; 178 config_found(self, &iba, iicbus_print); 179 180 return; 181 182 fail: 183 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 184 } 185 186 int 187 gpioiic_detach(struct device *self, int flags) 188 { 189 return (0); 190 } 191 192 int 193 gpioiic_i2c_acquire_bus(void *cookie, int flags) 194 { 195 struct gpioiic_softc *sc = cookie; 196 197 if (cold || (flags & I2C_F_POLL)) 198 return (0); 199 200 return (lockmgr(&sc->sc_i2c_lock, LK_EXCLUSIVE, NULL)); 201 } 202 203 void 204 gpioiic_i2c_release_bus(void *cookie, int flags) 205 { 206 struct gpioiic_softc *sc = cookie; 207 208 if (cold || (flags & I2C_F_POLL)) 209 return; 210 211 lockmgr(&sc->sc_i2c_lock, LK_RELEASE, NULL); 212 } 213 214 int 215 gpioiic_i2c_send_start(void *cookie, int flags) 216 { 217 return (i2c_bitbang_send_start(cookie, flags, &gpioiic_bbops)); 218 } 219 220 int 221 gpioiic_i2c_send_stop(void *cookie, int flags) 222 { 223 return (i2c_bitbang_send_stop(cookie, flags, &gpioiic_bbops)); 224 } 225 226 int 227 gpioiic_i2c_initiate_xfer(void *cookie, i2c_addr_t addr, int flags) 228 { 229 return (i2c_bitbang_initiate_xfer(cookie, addr, flags, &gpioiic_bbops)); 230 } 231 232 int 233 gpioiic_i2c_read_byte(void *cookie, u_int8_t *bytep, int flags) 234 { 235 return (i2c_bitbang_read_byte(cookie, bytep, flags, &gpioiic_bbops)); 236 } 237 238 int 239 gpioiic_i2c_write_byte(void *cookie, u_int8_t byte, int flags) 240 { 241 return (i2c_bitbang_write_byte(cookie, byte, flags, &gpioiic_bbops)); 242 } 243 244 void 245 gpioiic_bb_set_bits(void *cookie, u_int32_t bits) 246 { 247 struct gpioiic_softc *sc = cookie; 248 249 gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, 250 bits & GPIOIIC_SDA ? GPIO_PIN_HIGH : GPIO_PIN_LOW); 251 gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SCL, 252 bits & GPIOIIC_SCL ? GPIO_PIN_HIGH : GPIO_PIN_LOW); 253 } 254 255 void 256 gpioiic_bb_set_dir(void *cookie, u_int32_t bits) 257 { 258 struct gpioiic_softc *sc = cookie; 259 260 if (!(sc->sc_sda & GPIO_PIN_OPENDRAIN)) { 261 sc->sc_sda &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); 262 sc->sc_sda |= (bits & GPIOIIC_SDA ? GPIO_PIN_OUTPUT : 263 GPIO_PIN_INPUT); 264 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOIIC_PIN_SDA, 265 sc->sc_sda); 266 } 267 } 268 269 u_int32_t 270 gpioiic_bb_read_bits(void *cookie) 271 { 272 struct gpioiic_softc *sc = cookie; 273 274 return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, 275 GPIOIIC_PIN_SDA) == GPIO_PIN_HIGH ? GPIOIIC_SDA : 0); 276 } 277