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