1 1.20 riastrad /* $NetBSD: gpioow.c,v 1.20 2023/05/10 00:09:31 riastradh Exp $ */ 2 1.1 riz /* $OpenBSD: gpioow.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ 3 1.1 riz 4 1.1 riz /* 5 1.1 riz * Copyright (c) 2006 Alexander Yurchenko <grange (at) openbsd.org> 6 1.1 riz * 7 1.1 riz * Permission to use, copy, modify, and distribute this software for any 8 1.1 riz * purpose with or without fee is hereby granted, provided that the above 9 1.1 riz * copyright notice and this permission notice appear in all copies. 10 1.1 riz * 11 1.1 riz * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 1.1 riz * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 1.1 riz * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 1.1 riz * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 1.1 riz * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 1.1 riz * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 1.1 riz * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 1.1 riz */ 19 1.1 riz 20 1.1 riz #include <sys/cdefs.h> 21 1.20 riastrad __KERNEL_RCSID(0, "$NetBSD: gpioow.c,v 1.20 2023/05/10 00:09:31 riastradh Exp $"); 22 1.1 riz 23 1.1 riz /* 24 1.1 riz * 1-Wire bus bit-banging through GPIO pin. 25 1.1 riz */ 26 1.1 riz 27 1.1 riz #include <sys/param.h> 28 1.1 riz #include <sys/systm.h> 29 1.1 riz #include <sys/device.h> 30 1.1 riz #include <sys/gpio.h> 31 1.13 mbalmer #include <sys/module.h> 32 1.1 riz 33 1.1 riz #include <dev/gpio/gpiovar.h> 34 1.1 riz 35 1.1 riz #include <dev/onewire/onewirevar.h> 36 1.1 riz 37 1.15 riastrad #include "ioconf.h" 38 1.15 riastrad 39 1.1 riz #define GPIOOW_NPINS 1 40 1.1 riz #define GPIOOW_PIN_DATA 0 41 1.1 riz 42 1.1 riz struct gpioow_softc { 43 1.1 riz void * sc_gpio; 44 1.1 riz struct gpio_pinmap sc_map; 45 1.10 mbalmer int _map[GPIOOW_NPINS]; 46 1.1 riz 47 1.1 riz struct onewire_bus sc_ow_bus; 48 1.5 xtraeme device_t sc_ow_dev; 49 1.1 riz 50 1.1 riz int sc_data; 51 1.1 riz int sc_dying; 52 1.1 riz }; 53 1.1 riz 54 1.17 maxv static int gpioow_match(device_t, cfdata_t, void *); 55 1.17 maxv static void gpioow_attach(device_t, device_t, void *); 56 1.17 maxv static int gpioow_detach(device_t, int); 57 1.17 maxv static int gpioow_activate(device_t, enum devact); 58 1.17 maxv 59 1.17 maxv static int gpioow_ow_reset(void *); 60 1.17 maxv static int gpioow_ow_read_bit(void *); 61 1.17 maxv static void gpioow_ow_write_bit(void *, int); 62 1.17 maxv 63 1.17 maxv static void gpioow_bb_rx(void *); 64 1.17 maxv static void gpioow_bb_tx(void *); 65 1.17 maxv static int gpioow_bb_get(void *); 66 1.17 maxv static void gpioow_bb_set(void *, int); 67 1.1 riz 68 1.5 xtraeme CFATTACH_DECL_NEW(gpioow, sizeof(struct gpioow_softc), 69 1.1 riz gpioow_match, gpioow_attach, gpioow_detach, gpioow_activate); 70 1.1 riz 71 1.1 riz static const struct onewire_bbops gpioow_bbops = { 72 1.1 riz gpioow_bb_rx, 73 1.1 riz gpioow_bb_tx, 74 1.1 riz gpioow_bb_get, 75 1.1 riz gpioow_bb_set 76 1.1 riz }; 77 1.1 riz 78 1.17 maxv static int 79 1.9 mbalmer gpioow_match(device_t parent, cfdata_t cf, void *aux) 80 1.1 riz { 81 1.7 mbalmer struct gpio_attach_args *ga = aux; 82 1.7 mbalmer 83 1.8 mbalmer if (strcmp(ga->ga_dvname, cf->cf_name)) 84 1.8 mbalmer return 0; 85 1.8 mbalmer 86 1.7 mbalmer if (ga->ga_offset == -1) 87 1.7 mbalmer return 0; 88 1.7 mbalmer 89 1.8 mbalmer /* Check that we have enough pins */ 90 1.8 mbalmer if (gpio_npins(ga->ga_mask) != GPIOOW_NPINS) { 91 1.14 mbalmer aprint_debug("%s: invalid pin mask 0x%02x\n", cf->cf_name, 92 1.8 mbalmer ga->ga_mask); 93 1.8 mbalmer return 0; 94 1.8 mbalmer } 95 1.8 mbalmer return 1; 96 1.1 riz } 97 1.1 riz 98 1.17 maxv static void 99 1.4 cegger gpioow_attach(device_t parent, device_t self, void *aux) 100 1.1 riz { 101 1.1 riz struct gpioow_softc *sc = device_private(self); 102 1.1 riz struct gpio_attach_args *ga = aux; 103 1.1 riz struct onewirebus_attach_args oba; 104 1.1 riz int caps; 105 1.1 riz 106 1.1 riz /* Map pins */ 107 1.1 riz sc->sc_gpio = ga->ga_gpio; 108 1.10 mbalmer sc->sc_map.pm_map = sc->_map; 109 1.1 riz if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 110 1.1 riz &sc->sc_map)) { 111 1.8 mbalmer aprint_error(": can't map pins\n"); 112 1.13 mbalmer goto finish; 113 1.1 riz } 114 1.1 riz 115 1.1 riz /* Configure data pin */ 116 1.1 riz caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA); 117 1.1 riz if (!(caps & GPIO_PIN_OUTPUT)) { 118 1.8 mbalmer aprint_error(": data pin is unable to drive output\n"); 119 1.13 mbalmer gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 120 1.13 mbalmer goto finish; 121 1.1 riz } 122 1.1 riz if (!(caps & GPIO_PIN_INPUT)) { 123 1.8 mbalmer aprint_error(": data pin is unable to read input\n"); 124 1.13 mbalmer gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 125 1.13 mbalmer goto finish; 126 1.1 riz } 127 1.8 mbalmer aprint_normal(": DATA[%d]", sc->sc_map.pm_map[GPIOOW_PIN_DATA]); 128 1.1 riz sc->sc_data = GPIO_PIN_OUTPUT; 129 1.1 riz if (caps & GPIO_PIN_OPENDRAIN) { 130 1.8 mbalmer aprint_normal(" open-drain"); 131 1.1 riz sc->sc_data |= GPIO_PIN_OPENDRAIN; 132 1.1 riz } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) { 133 1.8 mbalmer aprint_normal(" push-pull tri-state"); 134 1.1 riz sc->sc_data |= GPIO_PIN_PUSHPULL; 135 1.1 riz } 136 1.1 riz if (caps & GPIO_PIN_PULLUP) { 137 1.8 mbalmer aprint_normal(" pull-up"); 138 1.1 riz sc->sc_data |= GPIO_PIN_PULLUP; 139 1.1 riz } 140 1.1 riz gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, sc->sc_data); 141 1.1 riz 142 1.8 mbalmer aprint_normal("\n"); 143 1.1 riz 144 1.1 riz /* Attach 1-Wire bus */ 145 1.1 riz sc->sc_ow_bus.bus_cookie = sc; 146 1.1 riz sc->sc_ow_bus.bus_reset = gpioow_ow_reset; 147 1.16 ad sc->sc_ow_bus.bus_read_bit = gpioow_ow_read_bit; 148 1.16 ad sc->sc_ow_bus.bus_write_bit = gpioow_ow_write_bit; 149 1.1 riz 150 1.6 cegger memset(&oba, 0, sizeof(oba)); 151 1.1 riz oba.oba_bus = &sc->sc_ow_bus; 152 1.19 thorpej sc->sc_ow_dev = config_found(self, &oba, onewirebus_print, CFARGS_NONE); 153 1.1 riz 154 1.11 mbalmer if (!pmf_device_register(self, NULL, NULL)) 155 1.11 mbalmer aprint_error("%s: could not establish power handler\n", 156 1.11 mbalmer device_xname(self)); 157 1.13 mbalmer finish: 158 1.1 riz return; 159 1.1 riz } 160 1.1 riz 161 1.17 maxv static int 162 1.4 cegger gpioow_detach(device_t self, int flags) 163 1.1 riz { 164 1.1 riz struct gpioow_softc *sc = device_private(self); 165 1.20 riastrad int error; 166 1.1 riz 167 1.20 riastrad error = config_detach_children(self, flags); 168 1.20 riastrad if (error) 169 1.20 riastrad return error; 170 1.20 riastrad 171 1.20 riastrad gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 172 1.20 riastrad pmf_device_deregister(self); 173 1.20 riastrad return 0; 174 1.1 riz } 175 1.1 riz 176 1.17 maxv static int 177 1.4 cegger gpioow_activate(device_t self, enum devact act) 178 1.1 riz { 179 1.1 riz struct gpioow_softc *sc = device_private(self); 180 1.1 riz 181 1.1 riz switch (act) { 182 1.1 riz case DVACT_DEACTIVATE: 183 1.1 riz sc->sc_dying = 1; 184 1.12 dyoung return 0; 185 1.12 dyoung default: 186 1.12 dyoung return EOPNOTSUPP; 187 1.1 riz } 188 1.1 riz } 189 1.1 riz 190 1.17 maxv static int 191 1.1 riz gpioow_ow_reset(void *arg) 192 1.1 riz { 193 1.1 riz return (onewire_bb_reset(&gpioow_bbops, arg)); 194 1.1 riz } 195 1.1 riz 196 1.17 maxv static int 197 1.16 ad gpioow_ow_read_bit(void *arg) 198 1.1 riz { 199 1.16 ad return (onewire_bb_read_bit(&gpioow_bbops, arg)); 200 1.16 ad } 201 1.16 ad 202 1.17 maxv static void 203 1.16 ad gpioow_ow_write_bit(void *arg, int value) 204 1.16 ad { 205 1.16 ad onewire_bb_write_bit(&gpioow_bbops, arg, value); 206 1.1 riz } 207 1.1 riz 208 1.17 maxv static void 209 1.1 riz gpioow_bb_rx(void *arg) 210 1.1 riz { 211 1.1 riz struct gpioow_softc *sc = arg; 212 1.1 riz int data = sc->sc_data; 213 1.1 riz 214 1.1 riz data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 215 1.1 riz data |= GPIO_PIN_INPUT; 216 1.1 riz if (data & GPIO_PIN_PUSHPULL) 217 1.1 riz data |= GPIO_PIN_TRISTATE; 218 1.1 riz if (sc->sc_data != data) { 219 1.1 riz sc->sc_data = data; 220 1.1 riz gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 221 1.1 riz sc->sc_data); 222 1.1 riz } 223 1.1 riz } 224 1.1 riz 225 1.17 maxv static void 226 1.1 riz gpioow_bb_tx(void *arg) 227 1.1 riz { 228 1.1 riz struct gpioow_softc *sc = arg; 229 1.1 riz int data = sc->sc_data; 230 1.1 riz 231 1.1 riz data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 232 1.1 riz data |= GPIO_PIN_OUTPUT; 233 1.1 riz if (sc->sc_data != data) { 234 1.1 riz sc->sc_data = data; 235 1.1 riz gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 236 1.1 riz sc->sc_data); 237 1.1 riz } 238 1.1 riz } 239 1.1 riz 240 1.17 maxv static int 241 1.1 riz gpioow_bb_get(void *arg) 242 1.1 riz { 243 1.1 riz struct gpioow_softc *sc = arg; 244 1.1 riz 245 1.1 riz return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA) == 246 1.1 riz GPIO_PIN_HIGH ? 1 : 0); 247 1.1 riz } 248 1.1 riz 249 1.17 maxv static void 250 1.1 riz gpioow_bb_set(void *arg, int value) 251 1.1 riz { 252 1.1 riz struct gpioow_softc *sc = arg; 253 1.1 riz 254 1.1 riz gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 255 1.1 riz value ? GPIO_PIN_HIGH : GPIO_PIN_LOW); 256 1.1 riz } 257 1.13 mbalmer 258 1.13 mbalmer MODULE(MODULE_CLASS_DRIVER, gpioow, "gpio,onewire"); 259 1.13 mbalmer 260 1.13 mbalmer #ifdef _MODULE 261 1.13 mbalmer #include "ioconf.c" 262 1.13 mbalmer #endif 263 1.13 mbalmer 264 1.13 mbalmer static int 265 1.13 mbalmer gpioow_modcmd(modcmd_t cmd, void *opaque) 266 1.13 mbalmer { 267 1.13 mbalmer int error; 268 1.13 mbalmer 269 1.13 mbalmer error = 0; 270 1.13 mbalmer switch (cmd) { 271 1.13 mbalmer case MODULE_CMD_INIT: 272 1.13 mbalmer #ifdef _MODULE 273 1.13 mbalmer error = config_init_component(cfdriver_ioconf_gpioow, 274 1.13 mbalmer cfattach_ioconf_gpioow, cfdata_ioconf_gpioow); 275 1.13 mbalmer if (error) 276 1.13 mbalmer aprint_error("%s: unable to init component\n", 277 1.13 mbalmer gpioow_cd.cd_name); 278 1.13 mbalmer #endif 279 1.13 mbalmer break; 280 1.13 mbalmer case MODULE_CMD_FINI: 281 1.13 mbalmer #ifdef _MODULE 282 1.13 mbalmer config_fini_component(cfdriver_ioconf_gpioow, 283 1.13 mbalmer cfattach_ioconf_gpioow, cfdata_ioconf_gpioow); 284 1.13 mbalmer #endif 285 1.13 mbalmer break; 286 1.13 mbalmer default: 287 1.13 mbalmer error = ENOTTY; 288 1.13 mbalmer } 289 1.13 mbalmer return error; 290 1.13 mbalmer } 291