gpio.c revision 1.16 1 1.16 cegger /* $NetBSD: gpio.c,v 1.16 2008/04/29 14:07:36 cegger Exp $ */
2 1.5 riz /* $OpenBSD: gpio.c,v 1.6 2006/01/14 12:33:49 grange Exp $ */
3 1.5 riz
4 1.1 jmcneill /*
5 1.5 riz * Copyright (c) 2004, 2006 Alexander Yurchenko <grange (at) openbsd.org>
6 1.1 jmcneill *
7 1.1 jmcneill * Permission to use, copy, modify, and distribute this software for any
8 1.1 jmcneill * purpose with or without fee is hereby granted, provided that the above
9 1.1 jmcneill * copyright notice and this permission notice appear in all copies.
10 1.1 jmcneill *
11 1.1 jmcneill * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 1.1 jmcneill * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 1.1 jmcneill * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 1.1 jmcneill * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 1.1 jmcneill * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 1.1 jmcneill * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 1.1 jmcneill * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 1.1 jmcneill */
19 1.1 jmcneill
20 1.2 cube #include <sys/cdefs.h>
21 1.16 cegger __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.16 2008/04/29 14:07:36 cegger Exp $");
22 1.2 cube
23 1.1 jmcneill /*
24 1.1 jmcneill * General Purpose Input/Output framework.
25 1.1 jmcneill */
26 1.1 jmcneill
27 1.1 jmcneill #include <sys/param.h>
28 1.1 jmcneill #include <sys/systm.h>
29 1.1 jmcneill #include <sys/conf.h>
30 1.1 jmcneill #include <sys/device.h>
31 1.1 jmcneill #include <sys/ioctl.h>
32 1.1 jmcneill #include <sys/gpio.h>
33 1.1 jmcneill #include <sys/vnode.h>
34 1.1 jmcneill
35 1.1 jmcneill #include <dev/gpio/gpiovar.h>
36 1.1 jmcneill
37 1.3 drochner #include "locators.h"
38 1.3 drochner
39 1.1 jmcneill struct gpio_softc {
40 1.1 jmcneill struct device sc_dev;
41 1.1 jmcneill
42 1.1 jmcneill gpio_chipset_tag_t sc_gc; /* our GPIO controller */
43 1.1 jmcneill gpio_pin_t *sc_pins; /* pins array */
44 1.1 jmcneill int sc_npins; /* total number of pins */
45 1.1 jmcneill
46 1.1 jmcneill int sc_opened;
47 1.1 jmcneill int sc_dying;
48 1.1 jmcneill };
49 1.1 jmcneill
50 1.14 dyoung int gpio_match(device_t, struct cfdata *, void *);
51 1.14 dyoung void gpio_attach(device_t, device_t, void *);
52 1.15 dyoung bool gpio_resume(device_t PMF_FN_PROTO);
53 1.14 dyoung int gpio_detach(device_t, int);
54 1.14 dyoung int gpio_activate(device_t, enum devact);
55 1.14 dyoung int gpio_search(device_t, struct cfdata *, const int *, void *);
56 1.1 jmcneill int gpio_print(void *, const char *);
57 1.1 jmcneill
58 1.1 jmcneill CFATTACH_DECL(gpio, sizeof(struct gpio_softc),
59 1.1 jmcneill gpio_match, gpio_attach, gpio_detach, gpio_activate);
60 1.1 jmcneill
61 1.1 jmcneill dev_type_open(gpioopen);
62 1.1 jmcneill dev_type_close(gpioclose);
63 1.1 jmcneill dev_type_ioctl(gpioioctl);
64 1.1 jmcneill
65 1.1 jmcneill const struct cdevsw gpio_cdevsw = {
66 1.1 jmcneill gpioopen, gpioclose, noread, nowrite, gpioioctl,
67 1.9 christos nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
68 1.1 jmcneill };
69 1.1 jmcneill
70 1.1 jmcneill extern struct cfdriver gpio_cd;
71 1.1 jmcneill
72 1.1 jmcneill int
73 1.14 dyoung gpio_match(device_t parent, struct cfdata *cf, void *aux)
74 1.1 jmcneill {
75 1.1 jmcneill
76 1.1 jmcneill return (1);
77 1.1 jmcneill }
78 1.1 jmcneill
79 1.13 dyoung bool
80 1.15 dyoung gpio_resume(device_t self PMF_FN_ARGS)
81 1.13 dyoung {
82 1.13 dyoung struct gpio_softc *sc = device_private(self);
83 1.13 dyoung int pin;
84 1.13 dyoung
85 1.13 dyoung for (pin = 0; pin < sc->sc_npins; pin++) {
86 1.13 dyoung gpiobus_pin_ctl(sc->sc_gc, pin, sc->sc_pins[pin].pin_flags);
87 1.13 dyoung gpiobus_pin_write(sc->sc_gc, pin, sc->sc_pins[pin].pin_state);
88 1.13 dyoung }
89 1.13 dyoung return true;
90 1.13 dyoung }
91 1.13 dyoung
92 1.1 jmcneill void
93 1.14 dyoung gpio_attach(device_t parent, device_t self, void *aux)
94 1.1 jmcneill {
95 1.7 thorpej struct gpio_softc *sc = device_private(self);
96 1.1 jmcneill struct gpiobus_attach_args *gba = aux;
97 1.1 jmcneill
98 1.1 jmcneill sc->sc_gc = gba->gba_gc;
99 1.1 jmcneill sc->sc_pins = gba->gba_pins;
100 1.1 jmcneill sc->sc_npins = gba->gba_npins;
101 1.1 jmcneill
102 1.1 jmcneill printf(": %d pins\n", sc->sc_npins);
103 1.1 jmcneill
104 1.13 dyoung if (!pmf_device_register(self, NULL, gpio_resume))
105 1.13 dyoung aprint_error_dev(self, "couldn't establish power handler\n");
106 1.13 dyoung
107 1.1 jmcneill /*
108 1.1 jmcneill * Attach all devices that can be connected to the GPIO pins
109 1.1 jmcneill * described in the kernel configuration file.
110 1.1 jmcneill */
111 1.5 riz config_search_ia(gpio_search, self, "gpio", sc);
112 1.1 jmcneill }
113 1.1 jmcneill
114 1.1 jmcneill int
115 1.14 dyoung gpio_detach(device_t self, int flags)
116 1.1 jmcneill {
117 1.1 jmcneill #if 0
118 1.1 jmcneill int maj, mn;
119 1.1 jmcneill
120 1.1 jmcneill /* Locate the major number */
121 1.1 jmcneill for (maj = 0; maj < nchrdev; maj++)
122 1.1 jmcneill if (cdevsw[maj].d_open == gpioopen)
123 1.1 jmcneill break;
124 1.1 jmcneill
125 1.1 jmcneill /* Nuke the vnodes for any open instances (calls close) */
126 1.6 thorpej mn = device_unit(self);
127 1.1 jmcneill vdevgone(maj, mn, mn, VCHR);
128 1.1 jmcneill #endif
129 1.1 jmcneill
130 1.1 jmcneill return (0);
131 1.1 jmcneill }
132 1.1 jmcneill
133 1.1 jmcneill int
134 1.14 dyoung gpio_activate(device_t self, enum devact act)
135 1.1 jmcneill {
136 1.7 thorpej struct gpio_softc *sc = device_private(self);
137 1.1 jmcneill
138 1.1 jmcneill switch (act) {
139 1.1 jmcneill case DVACT_ACTIVATE:
140 1.1 jmcneill return (EOPNOTSUPP);
141 1.1 jmcneill case DVACT_DEACTIVATE:
142 1.1 jmcneill sc->sc_dying = 1;
143 1.1 jmcneill break;
144 1.1 jmcneill }
145 1.1 jmcneill
146 1.1 jmcneill return (0);
147 1.1 jmcneill }
148 1.1 jmcneill
149 1.1 jmcneill int
150 1.14 dyoung gpio_search(device_t parent, struct cfdata *cf,
151 1.11 christos const int *ldesc, void *aux)
152 1.1 jmcneill {
153 1.1 jmcneill struct gpio_attach_args ga;
154 1.1 jmcneill
155 1.5 riz ga.ga_gpio = aux;
156 1.5 riz ga.ga_offset = cf->cf_loc[GPIOCF_OFFSET];
157 1.3 drochner ga.ga_mask = cf->cf_loc[GPIOCF_MASK];
158 1.1 jmcneill
159 1.1 jmcneill if (config_match(parent, cf, &ga) > 0)
160 1.1 jmcneill config_attach(parent, cf, &ga, gpio_print);
161 1.1 jmcneill
162 1.1 jmcneill return (0);
163 1.1 jmcneill }
164 1.1 jmcneill
165 1.1 jmcneill int
166 1.11 christos gpio_print(void *aux, const char *pnp)
167 1.1 jmcneill {
168 1.1 jmcneill struct gpio_attach_args *ga = aux;
169 1.1 jmcneill int i;
170 1.1 jmcneill
171 1.1 jmcneill printf(" pins");
172 1.1 jmcneill for (i = 0; i < 32; i++)
173 1.1 jmcneill if (ga->ga_mask & (1 << i))
174 1.5 riz printf(" %d", ga->ga_offset + i);
175 1.1 jmcneill
176 1.1 jmcneill return (UNCONF);
177 1.1 jmcneill }
178 1.1 jmcneill
179 1.1 jmcneill int
180 1.11 christos gpiobus_print(void *aux, const char *pnp)
181 1.1 jmcneill {
182 1.3 drochner #if 0
183 1.1 jmcneill struct gpiobus_attach_args *gba = aux;
184 1.3 drochner #endif
185 1.1 jmcneill if (pnp != NULL)
186 1.3 drochner printf("%s at %s", "gpiobus", pnp);
187 1.1 jmcneill
188 1.1 jmcneill return (UNCONF);
189 1.1 jmcneill }
190 1.1 jmcneill
191 1.8 uwe int
192 1.5 riz gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map)
193 1.5 riz {
194 1.5 riz struct gpio_softc *sc = gpio;
195 1.5 riz int npins, pin, i;
196 1.5 riz
197 1.5 riz npins = gpio_npins(mask);
198 1.5 riz if (npins > sc->sc_npins)
199 1.5 riz return (1);
200 1.5 riz
201 1.5 riz for (npins = 0, i = 0; i < 32; i++)
202 1.5 riz if (mask & (1 << i)) {
203 1.5 riz pin = offset + i;
204 1.5 riz if (pin < 0 || pin >= sc->sc_npins)
205 1.5 riz return (1);
206 1.5 riz if (sc->sc_pins[pin].pin_mapped)
207 1.5 riz return (1);
208 1.5 riz sc->sc_pins[pin].pin_mapped = 1;
209 1.5 riz map->pm_map[npins++] = pin;
210 1.5 riz }
211 1.5 riz map->pm_size = npins;
212 1.5 riz
213 1.5 riz return (0);
214 1.5 riz }
215 1.5 riz
216 1.5 riz void
217 1.5 riz gpio_pin_unmap(void *gpio, struct gpio_pinmap *map)
218 1.5 riz {
219 1.5 riz struct gpio_softc *sc = gpio;
220 1.5 riz int pin, i;
221 1.5 riz
222 1.5 riz for (i = 0; i < map->pm_size; i++) {
223 1.5 riz pin = map->pm_map[i];
224 1.5 riz sc->sc_pins[pin].pin_mapped = 0;
225 1.5 riz }
226 1.5 riz }
227 1.5 riz
228 1.5 riz int
229 1.5 riz gpio_pin_read(void *gpio, struct gpio_pinmap *map, int pin)
230 1.5 riz {
231 1.5 riz struct gpio_softc *sc = gpio;
232 1.5 riz
233 1.5 riz return (gpiobus_pin_read(sc->sc_gc, map->pm_map[pin]));
234 1.5 riz }
235 1.5 riz
236 1.5 riz void
237 1.5 riz gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value)
238 1.5 riz {
239 1.5 riz struct gpio_softc *sc = gpio;
240 1.5 riz
241 1.13 dyoung gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value);
242 1.13 dyoung sc->sc_pins[map->pm_map[pin]].pin_state = value;
243 1.5 riz }
244 1.5 riz
245 1.5 riz void
246 1.5 riz gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags)
247 1.5 riz {
248 1.5 riz struct gpio_softc *sc = gpio;
249 1.5 riz
250 1.5 riz return (gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags));
251 1.5 riz }
252 1.5 riz
253 1.5 riz int
254 1.5 riz gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin)
255 1.5 riz {
256 1.5 riz struct gpio_softc *sc = gpio;
257 1.5 riz
258 1.5 riz return (sc->sc_pins[map->pm_map[pin]].pin_caps);
259 1.5 riz }
260 1.5 riz
261 1.5 riz int
262 1.5 riz gpio_npins(u_int32_t mask)
263 1.5 riz {
264 1.5 riz int npins, i;
265 1.5 riz
266 1.5 riz for (npins = 0, i = 0; i < 32; i++)
267 1.5 riz if (mask & (1 << i))
268 1.5 riz npins++;
269 1.5 riz
270 1.5 riz return (npins);
271 1.5 riz }
272 1.5 riz
273 1.1 jmcneill int
274 1.11 christos gpioopen(dev_t dev, int flag, int mode,
275 1.11 christos struct lwp *l)
276 1.1 jmcneill {
277 1.1 jmcneill struct gpio_softc *sc;
278 1.16 cegger int ret;
279 1.1 jmcneill
280 1.1 jmcneill sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
281 1.1 jmcneill if (sc == NULL)
282 1.1 jmcneill return (ENXIO);
283 1.1 jmcneill
284 1.1 jmcneill if (sc->sc_opened)
285 1.1 jmcneill return (EBUSY);
286 1.16 cegger
287 1.16 cegger if ((ret = gpiobus_open(sc->sc_gc, &sc->sc_dev)))
288 1.16 cegger return ret;
289 1.16 cegger
290 1.1 jmcneill sc->sc_opened = 1;
291 1.1 jmcneill
292 1.1 jmcneill return (0);
293 1.1 jmcneill }
294 1.1 jmcneill
295 1.1 jmcneill int
296 1.11 christos gpioclose(dev_t dev, int flag, int mode,
297 1.11 christos struct lwp *l)
298 1.1 jmcneill {
299 1.1 jmcneill struct gpio_softc *sc;
300 1.1 jmcneill
301 1.1 jmcneill sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
302 1.16 cegger gpiobus_close(sc->sc_gc, &sc->sc_dev);
303 1.1 jmcneill sc->sc_opened = 0;
304 1.1 jmcneill
305 1.1 jmcneill return (0);
306 1.1 jmcneill }
307 1.1 jmcneill
308 1.1 jmcneill int
309 1.12 christos gpioioctl(dev_t dev, u_long cmd, void *data, int flag,
310 1.11 christos struct lwp *l)
311 1.1 jmcneill {
312 1.1 jmcneill struct gpio_softc *sc;
313 1.1 jmcneill gpio_chipset_tag_t gc;
314 1.1 jmcneill struct gpio_info *info;
315 1.1 jmcneill struct gpio_pin_op *op;
316 1.1 jmcneill struct gpio_pin_ctl *ctl;
317 1.1 jmcneill int pin, value, flags;
318 1.1 jmcneill
319 1.1 jmcneill sc = (struct gpio_softc *)device_lookup(&gpio_cd, minor(dev));
320 1.1 jmcneill gc = sc->sc_gc;
321 1.1 jmcneill
322 1.13 dyoung if (cmd != GPIOINFO && !device_is_active(&sc->sc_dev))
323 1.13 dyoung return EBUSY;
324 1.13 dyoung
325 1.1 jmcneill switch (cmd) {
326 1.1 jmcneill case GPIOINFO:
327 1.1 jmcneill info = (struct gpio_info *)data;
328 1.1 jmcneill
329 1.1 jmcneill info->gpio_npins = sc->sc_npins;
330 1.1 jmcneill break;
331 1.1 jmcneill case GPIOPINREAD:
332 1.1 jmcneill op = (struct gpio_pin_op *)data;
333 1.1 jmcneill
334 1.1 jmcneill pin = op->gp_pin;
335 1.1 jmcneill if (pin < 0 || pin >= sc->sc_npins)
336 1.1 jmcneill return (EINVAL);
337 1.1 jmcneill
338 1.1 jmcneill /* return read value */
339 1.1 jmcneill op->gp_value = gpiobus_pin_read(gc, pin);
340 1.1 jmcneill break;
341 1.1 jmcneill case GPIOPINWRITE:
342 1.1 jmcneill op = (struct gpio_pin_op *)data;
343 1.1 jmcneill
344 1.1 jmcneill pin = op->gp_pin;
345 1.1 jmcneill if (pin < 0 || pin >= sc->sc_npins)
346 1.1 jmcneill return (EINVAL);
347 1.5 riz if (sc->sc_pins[pin].pin_mapped)
348 1.5 riz return (EBUSY);
349 1.1 jmcneill
350 1.1 jmcneill value = op->gp_value;
351 1.1 jmcneill if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
352 1.1 jmcneill return (EINVAL);
353 1.1 jmcneill
354 1.1 jmcneill gpiobus_pin_write(gc, pin, value);
355 1.1 jmcneill /* return old value */
356 1.1 jmcneill op->gp_value = sc->sc_pins[pin].pin_state;
357 1.1 jmcneill /* update current value */
358 1.1 jmcneill sc->sc_pins[pin].pin_state = value;
359 1.1 jmcneill break;
360 1.1 jmcneill case GPIOPINTOGGLE:
361 1.1 jmcneill op = (struct gpio_pin_op *)data;
362 1.1 jmcneill
363 1.1 jmcneill pin = op->gp_pin;
364 1.1 jmcneill if (pin < 0 || pin >= sc->sc_npins)
365 1.1 jmcneill return (EINVAL);
366 1.5 riz if (sc->sc_pins[pin].pin_mapped)
367 1.5 riz return (EBUSY);
368 1.1 jmcneill
369 1.1 jmcneill value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
370 1.1 jmcneill GPIO_PIN_HIGH : GPIO_PIN_LOW);
371 1.1 jmcneill gpiobus_pin_write(gc, pin, value);
372 1.1 jmcneill /* return old value */
373 1.1 jmcneill op->gp_value = sc->sc_pins[pin].pin_state;
374 1.1 jmcneill /* update current value */
375 1.1 jmcneill sc->sc_pins[pin].pin_state = value;
376 1.1 jmcneill break;
377 1.1 jmcneill case GPIOPINCTL:
378 1.1 jmcneill ctl = (struct gpio_pin_ctl *)data;
379 1.1 jmcneill
380 1.1 jmcneill pin = ctl->gp_pin;
381 1.1 jmcneill if (pin < 0 || pin >= sc->sc_npins)
382 1.1 jmcneill return (EINVAL);
383 1.5 riz if (sc->sc_pins[pin].pin_mapped)
384 1.5 riz return (EBUSY);
385 1.1 jmcneill
386 1.1 jmcneill flags = ctl->gp_flags;
387 1.1 jmcneill /* check that the controller supports all requested flags */
388 1.1 jmcneill if ((flags & sc->sc_pins[pin].pin_caps) != flags)
389 1.1 jmcneill return (ENODEV);
390 1.1 jmcneill
391 1.1 jmcneill ctl->gp_caps = sc->sc_pins[pin].pin_caps;
392 1.1 jmcneill /* return old value */
393 1.1 jmcneill ctl->gp_flags = sc->sc_pins[pin].pin_flags;
394 1.1 jmcneill if (flags > 0) {
395 1.1 jmcneill gpiobus_pin_ctl(gc, pin, flags);
396 1.1 jmcneill /* update current value */
397 1.1 jmcneill sc->sc_pins[pin].pin_flags = flags;
398 1.1 jmcneill }
399 1.1 jmcneill break;
400 1.1 jmcneill default:
401 1.1 jmcneill return (ENOTTY);
402 1.1 jmcneill }
403 1.1 jmcneill
404 1.1 jmcneill return (0);
405 1.1 jmcneill }
406