1 /* $NetBSD: gpioow.c,v 1.14 2011/09/07 07:43:05 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.14 2011/09/07 07:43:05 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 #include <sys/module.h> 32 33 #include <dev/gpio/gpiovar.h> 34 35 #include <dev/onewire/onewirevar.h> 36 37 #define GPIOOW_NPINS 1 38 #define GPIOOW_PIN_DATA 0 39 40 struct gpioow_softc { 41 void * sc_gpio; 42 struct gpio_pinmap sc_map; 43 int _map[GPIOOW_NPINS]; 44 45 struct onewire_bus sc_ow_bus; 46 device_t sc_ow_dev; 47 48 int sc_data; 49 int sc_dying; 50 }; 51 52 int gpioow_match(device_t, cfdata_t, void *); 53 void gpioow_attach(device_t, device_t, void *); 54 int gpioow_detach(device_t, int); 55 int gpioow_activate(device_t, enum devact); 56 57 int gpioow_ow_reset(void *); 58 int gpioow_ow_bit(void *, int); 59 60 void gpioow_bb_rx(void *); 61 void gpioow_bb_tx(void *); 62 int gpioow_bb_get(void *); 63 void gpioow_bb_set(void *, int); 64 65 CFATTACH_DECL_NEW(gpioow, sizeof(struct gpioow_softc), 66 gpioow_match, gpioow_attach, gpioow_detach, gpioow_activate); 67 68 extern struct cfdriver gpioow_cd; 69 70 static const struct onewire_bbops gpioow_bbops = { 71 gpioow_bb_rx, 72 gpioow_bb_tx, 73 gpioow_bb_get, 74 gpioow_bb_set 75 }; 76 77 int 78 gpioow_match(device_t parent, cfdata_t cf, void *aux) 79 { 80 struct gpio_attach_args *ga = aux; 81 82 if (strcmp(ga->ga_dvname, cf->cf_name)) 83 return 0; 84 85 if (ga->ga_offset == -1) 86 return 0; 87 88 /* Check that we have enough pins */ 89 if (gpio_npins(ga->ga_mask) != GPIOOW_NPINS) { 90 aprint_debug("%s: invalid pin mask 0x%02x\n", cf->cf_name, 91 ga->ga_mask); 92 return 0; 93 } 94 return 1; 95 } 96 97 void 98 gpioow_attach(device_t parent, device_t self, void *aux) 99 { 100 struct gpioow_softc *sc = device_private(self); 101 struct gpio_attach_args *ga = aux; 102 struct onewirebus_attach_args oba; 103 int caps; 104 105 /* Map pins */ 106 sc->sc_gpio = ga->ga_gpio; 107 sc->sc_map.pm_map = sc->_map; 108 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 109 &sc->sc_map)) { 110 aprint_error(": can't map pins\n"); 111 goto finish; 112 } 113 114 /* Configure data pin */ 115 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA); 116 if (!(caps & GPIO_PIN_OUTPUT)) { 117 aprint_error(": data pin is unable to drive output\n"); 118 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 119 goto finish; 120 } 121 if (!(caps & GPIO_PIN_INPUT)) { 122 aprint_error(": data pin is unable to read input\n"); 123 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 124 goto finish; 125 } 126 aprint_normal(": DATA[%d]", sc->sc_map.pm_map[GPIOOW_PIN_DATA]); 127 sc->sc_data = GPIO_PIN_OUTPUT; 128 if (caps & GPIO_PIN_OPENDRAIN) { 129 aprint_normal(" open-drain"); 130 sc->sc_data |= GPIO_PIN_OPENDRAIN; 131 } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) { 132 aprint_normal(" push-pull tri-state"); 133 sc->sc_data |= GPIO_PIN_PUSHPULL; 134 } 135 if (caps & GPIO_PIN_PULLUP) { 136 aprint_normal(" 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 aprint_normal("\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 memset(&oba, 0, sizeof(oba)); 149 oba.oba_bus = &sc->sc_ow_bus; 150 sc->sc_ow_dev = config_found(self, &oba, onewirebus_print); 151 152 if (!pmf_device_register(self, NULL, NULL)) 153 aprint_error("%s: could not establish power handler\n", 154 device_xname(self)); 155 finish: 156 return; 157 } 158 159 int 160 gpioow_detach(device_t self, int flags) 161 { 162 struct gpioow_softc *sc = device_private(self); 163 int rv = 0; 164 165 if (sc->sc_ow_dev != NULL) 166 rv = config_detach(sc->sc_ow_dev, flags); 167 168 if (!rv) { 169 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 170 pmf_device_deregister(self); 171 } 172 return rv; 173 } 174 175 int 176 gpioow_activate(device_t self, enum devact act) 177 { 178 struct gpioow_softc *sc = device_private(self); 179 180 switch (act) { 181 case DVACT_DEACTIVATE: 182 sc->sc_dying = 1; 183 return 0; 184 default: 185 return EOPNOTSUPP; 186 } 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 251 MODULE(MODULE_CLASS_DRIVER, gpioow, "gpio,onewire"); 252 253 #ifdef _MODULE 254 #include "ioconf.c" 255 #endif 256 257 static int 258 gpioow_modcmd(modcmd_t cmd, void *opaque) 259 { 260 int error; 261 262 error = 0; 263 switch (cmd) { 264 case MODULE_CMD_INIT: 265 #ifdef _MODULE 266 error = config_init_component(cfdriver_ioconf_gpioow, 267 cfattach_ioconf_gpioow, cfdata_ioconf_gpioow); 268 if (error) 269 aprint_error("%s: unable to init component\n", 270 gpioow_cd.cd_name); 271 #endif 272 break; 273 case MODULE_CMD_FINI: 274 #ifdef _MODULE 275 config_fini_component(cfdriver_ioconf_gpioow, 276 cfattach_ioconf_gpioow, cfdata_ioconf_gpioow); 277 #endif 278 break; 279 default: 280 error = ENOTTY; 281 } 282 return error; 283 } 284