1 /* $NetBSD: gpio.c,v 1.4 2005/12/11 12:21:22 christos Exp $ */ 2 /* $OpenBSD: gpio.c,v 1.4 2004/11/23 21:18:37 grange Exp $ */ 3 /* 4 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/cdefs.h> 20 __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.4 2005/12/11 12:21:22 christos Exp $"); 21 22 /* 23 * General Purpose Input/Output framework. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/conf.h> 29 #include <sys/device.h> 30 #include <sys/ioctl.h> 31 #include <sys/gpio.h> 32 #include <sys/vnode.h> 33 34 #include <dev/gpio/gpiovar.h> 35 36 #include "locators.h" 37 38 struct gpio_softc { 39 struct device sc_dev; 40 41 gpio_chipset_tag_t sc_gc; /* our GPIO controller */ 42 gpio_pin_t *sc_pins; /* pins array */ 43 int sc_npins; /* total number of pins */ 44 45 int sc_opened; 46 int sc_dying; 47 }; 48 49 int gpio_match(struct device *, struct cfdata *, void *); 50 void gpio_attach(struct device *, struct device *, void *); 51 int gpio_detach(struct device *, int); 52 int gpio_activate(struct device *, enum devact); 53 int gpio_search(struct device *, struct cfdata *, const int *, void *); 54 int gpio_print(void *, const char *); 55 56 CFATTACH_DECL(gpio, sizeof(struct gpio_softc), 57 gpio_match, gpio_attach, gpio_detach, gpio_activate); 58 59 dev_type_open(gpioopen); 60 dev_type_close(gpioclose); 61 dev_type_ioctl(gpioioctl); 62 63 const struct cdevsw gpio_cdevsw = { 64 gpioopen, gpioclose, noread, nowrite, gpioioctl, 65 nostop, notty, nopoll, nommap, nokqfilter, 66 }; 67 68 extern struct cfdriver gpio_cd; 69 70 int 71 gpio_match(struct device *parent, struct cfdata *cf, void *aux) 72 { 73 74 return (1); 75 } 76 77 void 78 gpio_attach(struct device *parent, struct device *self, void *aux) 79 { 80 struct gpio_softc *sc = (struct gpio_softc *)self; 81 struct gpiobus_attach_args *gba = aux; 82 83 sc->sc_gc = gba->gba_gc; 84 sc->sc_pins = gba->gba_pins; 85 sc->sc_npins = gba->gba_npins; 86 87 printf(": %d pins\n", sc->sc_npins); 88 89 /* 90 * Attach all devices that can be connected to the GPIO pins 91 * described in the kernel configuration file. 92 */ 93 config_search_ia(gpio_search, self, "gpio", NULL); 94 } 95 96 int 97 gpio_detach(struct device *self, int flags) 98 { 99 #if 0 100 int maj, mn; 101 102 /* Locate the major number */ 103 for (maj = 0; maj < nchrdev; maj++) 104 if (cdevsw[maj].d_open == gpioopen) 105 break; 106 107 /* Nuke the vnodes for any open instances (calls close) */ 108 mn = self->dv_unit; 109 vdevgone(maj, mn, mn, VCHR); 110 #endif 111 112 return (0); 113 } 114 115 int 116 gpio_activate(struct device *self, enum devact act) 117 { 118 struct gpio_softc *sc = (struct gpio_softc *)self; 119 120 switch (act) { 121 case DVACT_ACTIVATE: 122 return (EOPNOTSUPP); 123 case DVACT_DEACTIVATE: 124 sc->sc_dying = 1; 125 break; 126 } 127 128 return (0); 129 } 130 131 int 132 gpio_search(struct device *parent, struct cfdata *cf, 133 const int *ldesc, void *aux) 134 { 135 struct gpio_attach_args ga; 136 137 ga.ga_pin = cf->cf_loc[GPIOCF_PIN]; 138 ga.ga_mask = cf->cf_loc[GPIOCF_MASK]; 139 140 if (config_match(parent, cf, &ga) > 0) 141 config_attach(parent, cf, &ga, gpio_print); 142 143 return (0); 144 } 145 146 int 147 gpio_print(void *aux, const char *pnp) 148 { 149 struct gpio_attach_args *ga = aux; 150 int i; 151 152 printf(" pins"); 153 for (i = 0; i < 32; i++) 154 if (ga->ga_mask & (1 << i)) 155 printf(" %d", ga->ga_pin + i); 156 157 return (UNCONF); 158 } 159 160 int 161 gpiobus_print(void *aux, const char *pnp) 162 { 163 #if 0 164 struct gpiobus_attach_args *gba = aux; 165 #endif 166 if (pnp != NULL) 167 printf("%s at %s", "gpiobus", pnp); 168 169 return (UNCONF); 170 } 171 172 int 173 gpioopen(dev_t dev, int flag, int mode, struct lwp *l) 174 { 175 struct gpio_softc *sc; 176 177 sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev)); 178 if (sc == NULL) 179 return (ENXIO); 180 181 if (sc->sc_opened) 182 return (EBUSY); 183 sc->sc_opened = 1; 184 185 return (0); 186 } 187 188 int 189 gpioclose(dev_t dev, int flag, int mode, struct lwp *l) 190 { 191 struct gpio_softc *sc; 192 193 sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev)); 194 sc->sc_opened = 0; 195 196 return (0); 197 } 198 199 int 200 gpioioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l) 201 { 202 struct gpio_softc *sc; 203 gpio_chipset_tag_t gc; 204 struct gpio_info *info; 205 struct gpio_pin_op *op; 206 struct gpio_pin_ctl *ctl; 207 int pin, value, flags; 208 209 sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev)); 210 gc = sc->sc_gc; 211 212 switch (cmd) { 213 case GPIOINFO: 214 info = (struct gpio_info *)data; 215 216 info->gpio_npins = sc->sc_npins; 217 break; 218 case GPIOPINREAD: 219 op = (struct gpio_pin_op *)data; 220 221 pin = op->gp_pin; 222 if (pin < 0 || pin >= sc->sc_npins) 223 return (EINVAL); 224 225 /* return read value */ 226 op->gp_value = gpiobus_pin_read(gc, pin); 227 break; 228 case GPIOPINWRITE: 229 op = (struct gpio_pin_op *)data; 230 231 pin = op->gp_pin; 232 if (pin < 0 || pin >= sc->sc_npins) 233 return (EINVAL); 234 235 value = op->gp_value; 236 if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH) 237 return (EINVAL); 238 239 gpiobus_pin_write(gc, pin, value); 240 /* return old value */ 241 op->gp_value = sc->sc_pins[pin].pin_state; 242 /* update current value */ 243 sc->sc_pins[pin].pin_state = value; 244 break; 245 case GPIOPINTOGGLE: 246 op = (struct gpio_pin_op *)data; 247 248 pin = op->gp_pin; 249 if (pin < 0 || pin >= sc->sc_npins) 250 return (EINVAL); 251 252 value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ? 253 GPIO_PIN_HIGH : GPIO_PIN_LOW); 254 gpiobus_pin_write(gc, pin, value); 255 /* return old value */ 256 op->gp_value = sc->sc_pins[pin].pin_state; 257 /* update current value */ 258 sc->sc_pins[pin].pin_state = value; 259 break; 260 case GPIOPINCTL: 261 ctl = (struct gpio_pin_ctl *)data; 262 263 pin = ctl->gp_pin; 264 if (pin < 0 || pin >= sc->sc_npins) 265 return (EINVAL); 266 267 flags = ctl->gp_flags; 268 /* check that the controller supports all requested flags */ 269 if ((flags & sc->sc_pins[pin].pin_caps) != flags) 270 return (ENODEV); 271 272 ctl->gp_caps = sc->sc_pins[pin].pin_caps; 273 /* return old value */ 274 ctl->gp_flags = sc->sc_pins[pin].pin_flags; 275 if (flags > 0) { 276 gpiobus_pin_ctl(gc, pin, flags); 277 /* update current value */ 278 sc->sc_pins[pin].pin_flags = flags; 279 } 280 break; 281 default: 282 return (ENOTTY); 283 } 284 285 return (0); 286 } 287