gpioow.c revision 1.18
133965Sjdp/* $NetBSD: gpioow.c,v 1.18 2021/04/24 23:36:54 thorpej Exp $ */ 278828Sobrien/* $OpenBSD: gpioow.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */ 333965Sjdp 478828Sobrien/* 578828Sobrien * Copyright (c) 2006 Alexander Yurchenko <grange@openbsd.org> 678828Sobrien * 778828Sobrien * Permission to use, copy, modify, and distribute this software for any 878828Sobrien * purpose with or without fee is hereby granted, provided that the above 978828Sobrien * copyright notice and this permission notice appear in all copies. 1078828Sobrien * 1178828Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1278828Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1378828Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1478828Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1578828Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1678828Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1778828Sobrien * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1878828Sobrien */ 1978828Sobrien 2033965Sjdp#include <sys/cdefs.h> 2133965Sjdp__KERNEL_RCSID(0, "$NetBSD: gpioow.c,v 1.18 2021/04/24 23:36:54 thorpej Exp $"); 2233965Sjdp 2333965Sjdp/* 2433965Sjdp * 1-Wire bus bit-banging through GPIO pin. 2533965Sjdp */ 2633965Sjdp 2733965Sjdp#include <sys/param.h> 2833965Sjdp#include <sys/systm.h> 2933965Sjdp#include <sys/device.h> 3033965Sjdp#include <sys/gpio.h> 3133965Sjdp#include <sys/module.h> 3233965Sjdp 3333965Sjdp#include <dev/gpio/gpiovar.h> 3433965Sjdp 3533965Sjdp#include <dev/onewire/onewirevar.h> 3633965Sjdp 3733965Sjdp#include "ioconf.h" 3833965Sjdp 3933965Sjdp#define GPIOOW_NPINS 1 4033965Sjdp#define GPIOOW_PIN_DATA 0 4133965Sjdp 4233965Sjdpstruct gpioow_softc { 4333965Sjdp void * sc_gpio; 4433965Sjdp struct gpio_pinmap sc_map; 4533965Sjdp int _map[GPIOOW_NPINS]; 4633965Sjdp 4733965Sjdp struct onewire_bus sc_ow_bus; 4833965Sjdp device_t sc_ow_dev; 4933965Sjdp 5033965Sjdp int sc_data; 5133965Sjdp int sc_dying; 5233965Sjdp}; 5333965Sjdp 5433965Sjdpstatic int gpioow_match(device_t, cfdata_t, void *); 5533965Sjdpstatic void gpioow_attach(device_t, device_t, void *); 5633965Sjdpstatic int gpioow_detach(device_t, int); 5733965Sjdpstatic int gpioow_activate(device_t, enum devact); 5833965Sjdp 5933965Sjdpstatic int gpioow_ow_reset(void *); 6033965Sjdpstatic int gpioow_ow_read_bit(void *); 6133965Sjdpstatic void gpioow_ow_write_bit(void *, int); 6233965Sjdp 6333965Sjdpstatic void gpioow_bb_rx(void *); 6433965Sjdpstatic void gpioow_bb_tx(void *); 6533965Sjdpstatic int gpioow_bb_get(void *); 6633965Sjdpstatic void gpioow_bb_set(void *, int); 6733965Sjdp 6833965SjdpCFATTACH_DECL_NEW(gpioow, sizeof(struct gpioow_softc), 6933965Sjdp gpioow_match, gpioow_attach, gpioow_detach, gpioow_activate); 7033965Sjdp 7133965Sjdpstatic const struct onewire_bbops gpioow_bbops = { 7233965Sjdp gpioow_bb_rx, 7333965Sjdp gpioow_bb_tx, 7433965Sjdp gpioow_bb_get, 7533965Sjdp gpioow_bb_set 7633965Sjdp}; 7733965Sjdp 7833965Sjdpstatic int 7933965Sjdpgpioow_match(device_t parent, cfdata_t cf, void *aux) 8033965Sjdp{ 8133965Sjdp struct gpio_attach_args *ga = aux; 8233965Sjdp 8333965Sjdp if (strcmp(ga->ga_dvname, cf->cf_name)) 8433965Sjdp return 0; 8533965Sjdp 8633965Sjdp if (ga->ga_offset == -1) 8733965Sjdp return 0; 8833965Sjdp 8933965Sjdp /* Check that we have enough pins */ 9033965Sjdp if (gpio_npins(ga->ga_mask) != GPIOOW_NPINS) { 9133965Sjdp aprint_debug("%s: invalid pin mask 0x%02x\n", cf->cf_name, 9233965Sjdp ga->ga_mask); 9333965Sjdp return 0; 9433965Sjdp } 9533965Sjdp return 1; 9633965Sjdp} 9733965Sjdp 9833965Sjdpstatic void 9933965Sjdpgpioow_attach(device_t parent, device_t self, void *aux) 10033965Sjdp{ 10133965Sjdp struct gpioow_softc *sc = device_private(self); 10233965Sjdp struct gpio_attach_args *ga = aux; 10333965Sjdp struct onewirebus_attach_args oba; 10433965Sjdp int caps; 10533965Sjdp 10633965Sjdp /* Map pins */ 10733965Sjdp sc->sc_gpio = ga->ga_gpio; 10833965Sjdp sc->sc_map.pm_map = sc->_map; 10933965Sjdp if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 11033965Sjdp &sc->sc_map)) { 11133965Sjdp aprint_error(": can't map pins\n"); 11233965Sjdp goto finish; 11333965Sjdp } 11433965Sjdp 11533965Sjdp /* Configure data pin */ 11633965Sjdp caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA); 11733965Sjdp if (!(caps & GPIO_PIN_OUTPUT)) { 11833965Sjdp aprint_error(": data pin is unable to drive output\n"); 11933965Sjdp gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 12033965Sjdp goto finish; 12133965Sjdp } 12233965Sjdp if (!(caps & GPIO_PIN_INPUT)) { 12333965Sjdp aprint_error(": data pin is unable to read input\n"); 12433965Sjdp gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 12533965Sjdp goto finish; 12633965Sjdp } 12733965Sjdp aprint_normal(": DATA[%d]", sc->sc_map.pm_map[GPIOOW_PIN_DATA]); 12833965Sjdp sc->sc_data = GPIO_PIN_OUTPUT; 12933965Sjdp if (caps & GPIO_PIN_OPENDRAIN) { 13033965Sjdp aprint_normal(" open-drain"); 13133965Sjdp sc->sc_data |= GPIO_PIN_OPENDRAIN; 13233965Sjdp } else if ((caps & GPIO_PIN_PUSHPULL) && (caps & GPIO_PIN_TRISTATE)) { 13333965Sjdp aprint_normal(" push-pull tri-state"); 13433965Sjdp sc->sc_data |= GPIO_PIN_PUSHPULL; 13533965Sjdp } 13633965Sjdp if (caps & GPIO_PIN_PULLUP) { 13733965Sjdp aprint_normal(" pull-up"); 13833965Sjdp sc->sc_data |= GPIO_PIN_PULLUP; 13933965Sjdp } 14033965Sjdp gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, sc->sc_data); 14133965Sjdp 14233965Sjdp aprint_normal("\n"); 14333965Sjdp 14433965Sjdp /* Attach 1-Wire bus */ 14533965Sjdp sc->sc_ow_bus.bus_cookie = sc; 14633965Sjdp sc->sc_ow_bus.bus_reset = gpioow_ow_reset; 14733965Sjdp sc->sc_ow_bus.bus_read_bit = gpioow_ow_read_bit; 14833965Sjdp sc->sc_ow_bus.bus_write_bit = gpioow_ow_write_bit; 14933965Sjdp 15033965Sjdp memset(&oba, 0, sizeof(oba)); 15133965Sjdp oba.oba_bus = &sc->sc_ow_bus; 15233965Sjdp sc->sc_ow_dev = config_found(self, &oba, onewirebus_print, CFARG_EOL); 15333965Sjdp 15433965Sjdp if (!pmf_device_register(self, NULL, NULL)) 15533965Sjdp aprint_error("%s: could not establish power handler\n", 15633965Sjdp device_xname(self)); 15733965Sjdpfinish: 15833965Sjdp return; 15933965Sjdp} 16033965Sjdp 16133965Sjdpstatic int 16233965Sjdpgpioow_detach(device_t self, int flags) 16333965Sjdp{ 16433965Sjdp struct gpioow_softc *sc = device_private(self); 16533965Sjdp int rv = 0; 16633965Sjdp 16733965Sjdp if (sc->sc_ow_dev != NULL) 16833965Sjdp rv = config_detach(sc->sc_ow_dev, flags); 16933965Sjdp 17033965Sjdp if (!rv) { 17133965Sjdp gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 17233965Sjdp pmf_device_deregister(self); 17333965Sjdp } 17433965Sjdp return rv; 17533965Sjdp} 17633965Sjdp 17733965Sjdpstatic int 17833965Sjdpgpioow_activate(device_t self, enum devact act) 17933965Sjdp{ 18033965Sjdp struct gpioow_softc *sc = device_private(self); 18133965Sjdp 18233965Sjdp switch (act) { 18333965Sjdp case DVACT_DEACTIVATE: 18433965Sjdp sc->sc_dying = 1; 18533965Sjdp return 0; 18633965Sjdp default: 18733965Sjdp return EOPNOTSUPP; 18833965Sjdp } 18933965Sjdp} 19033965Sjdp 19133965Sjdpstatic int 19233965Sjdpgpioow_ow_reset(void *arg) 19333965Sjdp{ 19433965Sjdp return (onewire_bb_reset(&gpioow_bbops, arg)); 19533965Sjdp} 19633965Sjdp 19733965Sjdpstatic int 19833965Sjdpgpioow_ow_read_bit(void *arg) 19933965Sjdp{ 20033965Sjdp return (onewire_bb_read_bit(&gpioow_bbops, arg)); 20133965Sjdp} 20233965Sjdp 20333965Sjdpstatic void 20433965Sjdpgpioow_ow_write_bit(void *arg, int value) 20533965Sjdp{ 20633965Sjdp onewire_bb_write_bit(&gpioow_bbops, arg, value); 20733965Sjdp} 20833965Sjdp 20933965Sjdpstatic void 21033965Sjdpgpioow_bb_rx(void *arg) 21133965Sjdp{ 21233965Sjdp struct gpioow_softc *sc = arg; 21333965Sjdp int data = sc->sc_data; 21433965Sjdp 21533965Sjdp data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 21633965Sjdp data |= GPIO_PIN_INPUT; 21733965Sjdp if (data & GPIO_PIN_PUSHPULL) 21833965Sjdp data |= GPIO_PIN_TRISTATE; 21933965Sjdp if (sc->sc_data != data) { 22033965Sjdp sc->sc_data = data; 22133965Sjdp gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 22233965Sjdp sc->sc_data); 22333965Sjdp } 22433965Sjdp} 22533965Sjdp 22633965Sjdpstatic void 22733965Sjdpgpioow_bb_tx(void *arg) 22833965Sjdp{ 22933965Sjdp struct gpioow_softc *sc = arg; 23033965Sjdp int data = sc->sc_data; 23133965Sjdp 23233965Sjdp data &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE); 23333965Sjdp data |= GPIO_PIN_OUTPUT; 23433965Sjdp if (sc->sc_data != data) { 23533965Sjdp sc->sc_data = data; 23633965Sjdp gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 23733965Sjdp sc->sc_data); 23833965Sjdp } 23933965Sjdp} 24033965Sjdp 24133965Sjdpstatic int 24233965Sjdpgpioow_bb_get(void *arg) 24333965Sjdp{ 24433965Sjdp struct gpioow_softc *sc = arg; 24533965Sjdp 24633965Sjdp return (gpio_pin_read(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA) == 24733965Sjdp GPIO_PIN_HIGH ? 1 : 0); 24833965Sjdp} 24933965Sjdp 25033965Sjdpstatic void 25133965Sjdpgpioow_bb_set(void *arg, int value) 25233965Sjdp{ 25333965Sjdp struct gpioow_softc *sc = arg; 25433965Sjdp 25533965Sjdp gpio_pin_write(sc->sc_gpio, &sc->sc_map, GPIOOW_PIN_DATA, 25633965Sjdp value ? GPIO_PIN_HIGH : GPIO_PIN_LOW); 25733965Sjdp} 25833965Sjdp 25933965SjdpMODULE(MODULE_CLASS_DRIVER, gpioow, "gpio,onewire"); 26033965Sjdp 26133965Sjdp#ifdef _MODULE 26233965Sjdp#include "ioconf.c" 26333965Sjdp#endif 26433965Sjdp 26533965Sjdpstatic int 26633965Sjdpgpioow_modcmd(modcmd_t cmd, void *opaque) 26733965Sjdp{ 26833965Sjdp int error; 26933965Sjdp 27033965Sjdp error = 0; 27133965Sjdp switch (cmd) { 27233965Sjdp case MODULE_CMD_INIT: 27333965Sjdp#ifdef _MODULE 27433965Sjdp error = config_init_component(cfdriver_ioconf_gpioow, 27533965Sjdp cfattach_ioconf_gpioow, cfdata_ioconf_gpioow); 27633965Sjdp if (error) 27733965Sjdp aprint_error("%s: unable to init component\n", 27833965Sjdp gpioow_cd.cd_name); 27933965Sjdp#endif 28033965Sjdp break; 28133965Sjdp case MODULE_CMD_FINI: 28233965Sjdp#ifdef _MODULE 28333965Sjdp config_fini_component(cfdriver_ioconf_gpioow, 28433965Sjdp cfattach_ioconf_gpioow, cfdata_ioconf_gpioow); 28533965Sjdp#endif 28633965Sjdp break; 28733965Sjdp default: 28833965Sjdp error = ENOTTY; 28933965Sjdp } 29033965Sjdp return error; 29133965Sjdp} 29233965Sjdp