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