1 /* $NetBSD: gpiolock.c,v 1.3 2009/12/06 22:33:44 dyoung Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Marc Balmer <marc@msys.ch> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /* 29 * Driver for multi-position keylocks on GPIO pins 30 */ 31 32 #include "opt_keylock.h" 33 34 #include <sys/param.h> 35 #include <sys/device.h> 36 #include <sys/gpio.h> 37 38 #include <dev/gpio/gpiovar.h> 39 #include <dev/keylock.h> 40 41 #define GPIOLOCK_MAXPINS 4 42 #define GPIOLOCK_MINPINS 2 43 44 struct gpiolock_softc { 45 void * sc_gpio; 46 struct gpio_pinmap sc_map; 47 int _map[GPIOLOCK_MAXPINS]; 48 49 int sc_npins; 50 int sc_data; 51 int sc_dying; 52 }; 53 54 int gpiolock_match(device_t, cfdata_t, void *); 55 void gpiolock_attach(device_t, device_t, void *); 56 int gpiolock_detach(device_t, int); 57 int gpiolock_activate(device_t, enum devact); 58 int gpiolock_position(void *); 59 60 CFATTACH_DECL_NEW(gpiolock, sizeof(struct gpiolock_softc), 61 gpiolock_match, gpiolock_attach, gpiolock_detach, gpiolock_activate); 62 63 extern struct cfdriver gpiolock_cd; 64 65 int 66 gpiolock_match(device_t parent, cfdata_t cf, 67 void *aux) 68 { 69 struct gpio_attach_args *ga = aux; 70 int npins; 71 72 if (strcmp(ga->ga_dvname, cf->cf_name)) 73 return 0; 74 75 if (ga->ga_offset == -1) 76 return 0; 77 78 /* Check number of pins */ 79 npins = gpio_npins(ga->ga_mask); 80 if (npins < GPIOLOCK_MINPINS || npins > GPIOLOCK_MAXPINS) { 81 aprint_debug("%s: invalid pin mask 0x%02x\n", cf->cf_name, 82 ga->ga_mask); 83 return 0; 84 } 85 86 return 1; 87 } 88 89 void 90 gpiolock_attach(device_t parent, device_t self, void *aux) 91 { 92 struct gpiolock_softc *sc = device_private(self); 93 struct gpio_attach_args *ga = aux; 94 int pin, caps; 95 96 sc->sc_npins = gpio_npins(ga->ga_mask); 97 98 /* Map pins */ 99 sc->sc_gpio = ga->ga_gpio; 100 sc->sc_map.pm_map = sc->_map; 101 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, ga->ga_mask, 102 &sc->sc_map)) { 103 aprint_error(": can't map pins\n"); 104 return; 105 } 106 107 /* Configure data pins */ 108 for (pin = 0; pin < sc->sc_npins; pin++) { 109 caps = gpio_pin_caps(sc->sc_gpio, &sc->sc_map, pin); 110 if (!(caps & GPIO_PIN_INPUT)) { 111 aprint_error(": data pin is unable to read input\n"); 112 goto fail; 113 } 114 aprint_normal(" [%d]", sc->sc_map.pm_map[pin]); 115 sc->sc_data = GPIO_PIN_INPUT; 116 gpio_pin_ctl(sc->sc_gpio, &sc->sc_map, pin, sc->sc_data); 117 } 118 119 #ifdef KEYLOCK 120 /* Register keylock */ 121 if (keylock_register(self, sc->sc_npins, gpiolock_position)) { 122 aprint_error(": can't register keylock\n"); 123 goto fail; 124 } 125 #endif 126 pmf_device_register(self, NULL, NULL); 127 128 aprint_normal("\n"); 129 return; 130 131 fail: 132 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 133 } 134 135 int 136 gpiolock_detach(device_t self, int flags) 137 { 138 struct gpiolock_softc *sc = device_private(self); 139 140 pmf_device_deregister(self); 141 #ifdef KEYLOCK 142 keylock_unregister(self, gpiolock_position); 143 #endif 144 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map); 145 146 return 0; 147 } 148 149 int 150 gpiolock_activate(device_t self, enum devact act) 151 { 152 struct gpiolock_softc *sc = device_private(self); 153 154 switch (act) { 155 case DVACT_DEACTIVATE: 156 sc->sc_dying = 1; 157 return 0; 158 default: 159 return EOPNOTSUPP; 160 } 161 162 } 163 164 int 165 gpiolock_position(void *arg) 166 { 167 struct gpiolock_softc *sc = device_private((device_t)arg); 168 int pos, pin; 169 170 for (pos = pin = 0; pin < sc->sc_npins; pin++) { 171 if (gpio_pin_read(sc->sc_gpio, &sc->sc_map, pin) == 172 GPIO_PIN_HIGH) 173 pos = pin + 1; 174 } 175 return pos; 176 } 177 178