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