1 /* $OpenBSD: gpioow.c,v 1.2 2006/06/23 06:27:11 miod 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 * 1-Wire bus bit-banging through GPIO pin. 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/onewire/onewirevar.h> 31 32 #define GPIOOW_NPINS 1 33 #define GPIOOW_PIN_DATA 0 34 35 struct gpioow_softc { 36 struct device sc_dev; 37 38 void * sc_gpio; 39 struct gpio_pinmap sc_map; 40 int __map[GPIOOW_NPINS]; 41 42 struct onewire_bus sc_ow_bus; 43 struct device * sc_ow_dev; 44 45 int sc_data; 46 int sc_dying; 47 }; 48 49 int gpioow_match(struct device *, void *, void *); 50 void gpioow_attach(struct device *, struct device *, void *); 51 int gpioow_detach(struct device *, int); 52 int gpioow_activate(struct device *, enum devact); 53 54 int gpioow_ow_reset(void *); 55 int gpioow_ow_bit(void *, int); 56 57 void gpioow_bb_rx(void *); 58 void gpioow_bb_tx(void *); 59 int gpioow_bb_get(void *); 60 void gpioow_bb_set(void *, int); 61 62 struct cfattach gpioow_ca = { 63 sizeof(struct gpioow_softc), 64 gpioow_match, 65 gpioow_attach, 66 gpioow_detach, 67 gpioow_activate 68 }; 69 70 struct cfdriver gpioow_cd = { 71 NULL, "gpioow", DV_DULL 72 }; 73 74 static const struct onewire_bbops gpioow_bbops = { 75 gpioow_bb_rx, 76 gpioow_bb_tx, 77 gpioow_bb_get, 78 gpioow_bb_set 79 }; 80 81 int 82 gpioow_match(struct device *parent, void *match, void *aux) 83 { 84 struct cfdata *cf = match; 85 86 return (strcmp(cf->cf_driver->cd_name, "gpioow") == 0); 87 } 88 89 void 90 gpioow_attach(struct device *parent, struct device *self, void *aux) 91 { 92 struct gpioow_softc *sc = (struct gpioow_softc *)self; 93 struct gpio_attach_args *ga = aux; 94 struct onewirebus_attach_args oba; 95 int caps; 96 97 /* Check that we have enough pins */ 98 if (gpio_npins(ga->ga_mask) != GPIOOW_NPINS) { 99 printf(": invalid pin mask\n"); 100 return; 101 } 102 103 /* Map pins */ 104 sc->sc_gpio = ga->ga_gpio; 105 sc->sc_map.pm_map = sc->__map; 106 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 107 &sc->sc_map)) { 108 printf(": can't map pins\n"); 109 return; 110 } 111 112 /* Configure data pin */ 113 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA); 114 if (!(caps & GPIO_PIN_OUTPUT)) { 115 printf(": data pin is unable to drive output\n"); 116 goto fail; 117 } 118 if (!(caps & GPIO_PIN_INPUT)) { 119 printf(": data pin is unable to read input\n"); 120 goto fail; 121 } 122 printf(": DATA[%d]", sc->sc_map.pm_map[GPIOOW_PIN_DATA]); 123 sc->sc_data = GPIO_PIN_OUTPUT; 124 if (caps & GPIO_PIN_OPENDRAIN) { 125 printf(" open-drain"); 126 sc->sc_data |= GPIO_PIN_OPENDRAIN; 127 } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) { 128 printf(" push-pull tri-state"); 129 sc->sc_data |= GPIO_PIN_PUSHPULL; 130 } 131 if (caps & GPIO_PIN_PULLUP) { 132 printf(" pull-up"); 133 sc->sc_data |= GPIO_PIN_PULLUP; 134 } 135 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, sc->sc_data); 136 137 printf("\n"); 138 139 /* Attach 1-Wire bus */ 140 sc->sc_ow_bus.bus_cookie = sc; 141 sc->sc_ow_bus.bus_reset = gpioow_ow_reset; 142 sc->sc_ow_bus.bus_bit = gpioow_ow_bit; 143 144 bzero(&oba, sizeof(oba)); 145 oba.oba_bus = &sc->sc_ow_bus; 146 sc->sc_ow_dev = config_found(self, &oba, onewirebus_print); 147 148 return; 149 150 fail: 151 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 152 } 153 154 int 155 gpioow_detach(struct device *self, int flags) 156 { 157 struct gpioow_softc *sc = (struct gpioow_softc *)self; 158 int rv = 0; 159 160 if (sc->sc_ow_dev != NULL) 161 rv = config_detach(sc->sc_ow_dev, flags); 162 163 return (rv); 164 } 165 166 int 167 gpioow_activate(struct device *self, enum devact act) 168 { 169 struct gpioow_softc *sc = (struct gpioow_softc *)self; 170 int rv = 0; 171 172 switch (act) { 173 case DVACT_ACTIVATE: 174 break; 175 case DVACT_DEACTIVATE: 176 sc->sc_dying = 1; 177 if (sc->sc_ow_dev != NULL) 178 rv = config_deactivate(sc->sc_ow_dev); 179 break; 180 } 181 182 return (rv); 183 } 184 185 int 186 gpioow_ow_reset(void *arg) 187 { 188 return (onewire_bb_reset(&gpioow_bbops, arg)); 189 } 190 191 int 192 gpioow_ow_bit(void *arg, int value) 193 { 194 return (onewire_bb_bit(&gpioow_bbops, arg, value)); 195 } 196 197 void 198 gpioow_bb_rx(void *arg) 199 { 200 struct gpioow_softc *sc = arg; 201 int data = sc->sc_data; 202 203 data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 204 data |= GPIO_PIN_INPUT; 205 if (data & GPIO_PIN_PUSHPULL) 206 data |= GPIO_PIN_TRISTATE; 207 if (sc->sc_data != data) { 208 sc->sc_data = data; 209 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 210 sc->sc_data); 211 } 212 } 213 214 void 215 gpioow_bb_tx(void *arg) 216 { 217 struct gpioow_softc *sc = arg; 218 int data = sc->sc_data; 219 220 data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 221 data |= GPIO_PIN_OUTPUT; 222 if (sc->sc_data != data) { 223 sc->sc_data = data; 224 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 225 sc->sc_data); 226 } 227 } 228 229 int 230 gpioow_bb_get(void *arg) 231 { 232 struct gpioow_softc *sc = arg; 233 234 return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA) == 235 GPIO_PIN_HIGH ? 1 : 0); 236 } 237 238 void 239 gpioow_bb_set(void *arg, int value) 240 { 241 struct gpioow_softc *sc = arg; 242 243 gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 244 value ? GPIO_PIN_HIGH : GPIO_PIN_LOW); 245 } 246