1 /* $OpenBSD: gpioow.c,v 1.6 2022/04/06 18:59:28 naddy 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 *, int); 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 const 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 struct gpio_attach_args *ga = aux; 86 87 if (ga->ga_offset == -1) 88 return 0; 89 90 return (strcmp(cf->cf_driver->cd_name, "gpioow") == 0); 91 } 92 93 void 94 gpioow_attach(struct device *parent, struct device *self, void *aux) 95 { 96 struct gpioow_softc *sc = (struct gpioow_softc *)self; 97 struct gpio_attach_args *ga = aux; 98 struct onewirebus_attach_args oba; 99 int caps; 100 101 /* Check that we have enough pins */ 102 if (gpio_npins(ga->ga_mask) != GPIOOW_NPINS) { 103 printf(": invalid pin mask\n"); 104 return; 105 } 106 107 /* Map pins */ 108 sc->sc_gpio = ga->ga_gpio; 109 sc->sc_map.pm_map = sc->__map; 110 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 111 &sc->sc_map)) { 112 printf(": can't map pins\n"); 113 return; 114 } 115 116 /* Configure data pin */ 117 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA); 118 if (!(caps & GPIO_PIN_OUTPUT)) { 119 printf(": data pin is unable to drive output\n"); 120 goto fail; 121 } 122 if (!(caps & GPIO_PIN_INPUT)) { 123 printf(": data pin is unable to read input\n"); 124 goto fail; 125 } 126 printf(": DATA[%d]", sc->sc_map.pm_map[GPIOOW_PIN_DATA]); 127 sc->sc_data = GPIO_PIN_OUTPUT; 128 if (caps & GPIO_PIN_OPENDRAIN) { 129 printf(" open-drain"); 130 sc->sc_data |= GPIO_PIN_OPENDRAIN; 131 } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) { 132 printf(" push-pull tri-state"); 133 sc->sc_data |= GPIO_PIN_PUSHPULL; 134 } 135 if (caps & GPIO_PIN_PULLUP) { 136 printf(" pull-up"); 137 sc->sc_data |= GPIO_PIN_PULLUP; 138 } 139 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, sc->sc_data); 140 141 printf("\n"); 142 143 /* Attach 1-Wire bus */ 144 sc->sc_ow_bus.bus_cookie = sc; 145 sc->sc_ow_bus.bus_reset = gpioow_ow_reset; 146 sc->sc_ow_bus.bus_bit = gpioow_ow_bit; 147 148 bzero(&oba, sizeof(oba)); 149 oba.oba_bus = &sc->sc_ow_bus; 150 sc->sc_ow_dev = config_found(self, &oba, onewirebus_print); 151 152 return; 153 154 fail: 155 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 156 } 157 158 int 159 gpioow_detach(struct device *self, int flags) 160 { 161 struct gpioow_softc *sc = (struct gpioow_softc *)self; 162 int rv = 0; 163 164 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 165 166 if (sc->sc_ow_dev != NULL) 167 rv = config_detach(sc->sc_ow_dev, flags); 168 169 return (rv); 170 } 171 172 int 173 gpioow_activate(struct device *self, int act) 174 { 175 struct gpioow_softc *sc = (struct gpioow_softc *)self; 176 int rv = 0; 177 178 switch (act) { 179 case DVACT_DEACTIVATE: 180 sc->sc_dying = 1; 181 if (sc->sc_ow_dev != NULL) 182 rv = config_deactivate(sc->sc_ow_dev); 183 break; 184 } 185 186 return (rv); 187 } 188 189 int 190 gpioow_ow_reset(void *arg) 191 { 192 return (onewire_bb_reset(&gpioow_bbops, arg)); 193 } 194 195 int 196 gpioow_ow_bit(void *arg, int value) 197 { 198 return (onewire_bb_bit(&gpioow_bbops, arg, value)); 199 } 200 201 void 202 gpioow_bb_rx(void *arg) 203 { 204 struct gpioow_softc *sc = arg; 205 int data = sc->sc_data; 206 207 data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 208 data |= GPIO_PIN_INPUT; 209 if (data & GPIO_PIN_PUSHPULL) 210 data |= GPIO_PIN_TRISTATE; 211 if (sc->sc_data != data) { 212 sc->sc_data = data; 213 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 214 sc->sc_data); 215 } 216 } 217 218 void 219 gpioow_bb_tx(void *arg) 220 { 221 struct gpioow_softc *sc = arg; 222 int data = sc->sc_data; 223 224 data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 225 data |= GPIO_PIN_OUTPUT; 226 if (sc->sc_data != data) { 227 sc->sc_data = data; 228 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 229 sc->sc_data); 230 } 231 } 232 233 int 234 gpioow_bb_get(void *arg) 235 { 236 struct gpioow_softc *sc = arg; 237 238 return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA) == 239 GPIO_PIN_HIGH ? 1 : 0); 240 } 241 242 void 243 gpioow_bb_set(void *arg, int value) 244 { 245 struct gpioow_softc *sc = arg; 246 247 gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 248 value ? GPIO_PIN_HIGH : GPIO_PIN_LOW); 249 } 250