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