gpio.c revision 1.18 1 1.18 dyoung /* $NetBSD: gpio.c,v 1.18 2009/04/02 00:09:33 dyoung 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.18 dyoung __KERNEL_RCSID(0, "$NetBSD: gpio.c,v 1.18 2009/04/02 00:09:33 dyoung 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.17 cegger device_t 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.17 cegger int gpio_match(device_t, cfdata_t, 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.17 cegger int gpio_search(device_t, cfdata_t, const int *, void *);
56 1.1 jmcneill int gpio_print(void *, const char *);
57 1.1 jmcneill
58 1.18 dyoung CFATTACH_DECL3_NEW(gpio, sizeof(struct gpio_softc),
59 1.18 dyoung gpio_match, gpio_attach, gpio_detach, gpio_activate, NULL, NULL,
60 1.18 dyoung DVF_DETACH_SHUTDOWN);
61 1.1 jmcneill
62 1.1 jmcneill dev_type_open(gpioopen);
63 1.1 jmcneill dev_type_close(gpioclose);
64 1.1 jmcneill dev_type_ioctl(gpioioctl);
65 1.1 jmcneill
66 1.1 jmcneill const struct cdevsw gpio_cdevsw = {
67 1.1 jmcneill gpioopen, gpioclose, noread, nowrite, gpioioctl,
68 1.9 christos nostop, notty, nopoll, nommap, nokqfilter, D_OTHER,
69 1.1 jmcneill };
70 1.1 jmcneill
71 1.1 jmcneill extern struct cfdriver gpio_cd;
72 1.1 jmcneill
73 1.1 jmcneill int
74 1.17 cegger gpio_match(device_t parent, cfdata_t cf, void *aux)
75 1.1 jmcneill {
76 1.1 jmcneill
77 1.1 jmcneill return (1);
78 1.1 jmcneill }
79 1.1 jmcneill
80 1.13 dyoung bool
81 1.15 dyoung gpio_resume(device_t self PMF_FN_ARGS)
82 1.13 dyoung {
83 1.13 dyoung struct gpio_softc *sc = device_private(self);
84 1.13 dyoung int pin;
85 1.13 dyoung
86 1.13 dyoung for (pin = 0; pin < sc->sc_npins; pin++) {
87 1.13 dyoung gpiobus_pin_ctl(sc->sc_gc, pin, sc->sc_pins[pin].pin_flags);
88 1.13 dyoung gpiobus_pin_write(sc->sc_gc, pin, sc->sc_pins[pin].pin_state);
89 1.13 dyoung }
90 1.13 dyoung return true;
91 1.13 dyoung }
92 1.13 dyoung
93 1.1 jmcneill void
94 1.14 dyoung gpio_attach(device_t parent, device_t self, void *aux)
95 1.1 jmcneill {
96 1.7 thorpej struct gpio_softc *sc = device_private(self);
97 1.1 jmcneill struct gpiobus_attach_args *gba = aux;
98 1.1 jmcneill
99 1.17 cegger sc->sc_dev = self;
100 1.1 jmcneill sc->sc_gc = gba->gba_gc;
101 1.1 jmcneill sc->sc_pins = gba->gba_pins;
102 1.1 jmcneill sc->sc_npins = gba->gba_npins;
103 1.1 jmcneill
104 1.1 jmcneill printf(": %d pins\n", sc->sc_npins);
105 1.1 jmcneill
106 1.13 dyoung if (!pmf_device_register(self, NULL, gpio_resume))
107 1.13 dyoung aprint_error_dev(self, "couldn't establish power handler\n");
108 1.13 dyoung
109 1.1 jmcneill /*
110 1.1 jmcneill * Attach all devices that can be connected to the GPIO pins
111 1.1 jmcneill * described in the kernel configuration file.
112 1.1 jmcneill */
113 1.5 riz config_search_ia(gpio_search, self, "gpio", sc);
114 1.1 jmcneill }
115 1.1 jmcneill
116 1.1 jmcneill int
117 1.14 dyoung gpio_detach(device_t self, int flags)
118 1.1 jmcneill {
119 1.1 jmcneill #if 0
120 1.1 jmcneill int maj, mn;
121 1.1 jmcneill
122 1.1 jmcneill /* Locate the major number */
123 1.1 jmcneill for (maj = 0; maj < nchrdev; maj++)
124 1.1 jmcneill if (cdevsw[maj].d_open == gpioopen)
125 1.1 jmcneill break;
126 1.1 jmcneill
127 1.1 jmcneill /* Nuke the vnodes for any open instances (calls close) */
128 1.6 thorpej mn = device_unit(self);
129 1.1 jmcneill vdevgone(maj, mn, mn, VCHR);
130 1.1 jmcneill #endif
131 1.1 jmcneill
132 1.1 jmcneill return (0);
133 1.1 jmcneill }
134 1.1 jmcneill
135 1.1 jmcneill int
136 1.14 dyoung gpio_activate(device_t self, enum devact act)
137 1.1 jmcneill {
138 1.7 thorpej struct gpio_softc *sc = device_private(self);
139 1.1 jmcneill
140 1.1 jmcneill switch (act) {
141 1.1 jmcneill case DVACT_ACTIVATE:
142 1.1 jmcneill return (EOPNOTSUPP);
143 1.1 jmcneill case DVACT_DEACTIVATE:
144 1.1 jmcneill sc->sc_dying = 1;
145 1.1 jmcneill break;
146 1.1 jmcneill }
147 1.1 jmcneill
148 1.1 jmcneill return (0);
149 1.1 jmcneill }
150 1.1 jmcneill
151 1.1 jmcneill int
152 1.17 cegger gpio_search(device_t parent, cfdata_t cf,
153 1.11 christos const int *ldesc, void *aux)
154 1.1 jmcneill {
155 1.1 jmcneill struct gpio_attach_args ga;
156 1.1 jmcneill
157 1.5 riz ga.ga_gpio = aux;
158 1.5 riz ga.ga_offset = cf->cf_loc[GPIOCF_OFFSET];
159 1.3 drochner ga.ga_mask = cf->cf_loc[GPIOCF_MASK];
160 1.1 jmcneill
161 1.1 jmcneill if (config_match(parent, cf, &ga) > 0)
162 1.1 jmcneill config_attach(parent, cf, &ga, gpio_print);
163 1.1 jmcneill
164 1.1 jmcneill return (0);
165 1.1 jmcneill }
166 1.1 jmcneill
167 1.1 jmcneill int
168 1.11 christos gpio_print(void *aux, const char *pnp)
169 1.1 jmcneill {
170 1.1 jmcneill struct gpio_attach_args *ga = aux;
171 1.1 jmcneill int i;
172 1.1 jmcneill
173 1.1 jmcneill printf(" pins");
174 1.1 jmcneill for (i = 0; i < 32; i++)
175 1.1 jmcneill if (ga->ga_mask & (1 << i))
176 1.5 riz printf(" %d", ga->ga_offset + i);
177 1.1 jmcneill
178 1.1 jmcneill return (UNCONF);
179 1.1 jmcneill }
180 1.1 jmcneill
181 1.1 jmcneill int
182 1.11 christos gpiobus_print(void *aux, const char *pnp)
183 1.1 jmcneill {
184 1.3 drochner #if 0
185 1.1 jmcneill struct gpiobus_attach_args *gba = aux;
186 1.3 drochner #endif
187 1.1 jmcneill if (pnp != NULL)
188 1.3 drochner printf("%s at %s", "gpiobus", pnp);
189 1.1 jmcneill
190 1.1 jmcneill return (UNCONF);
191 1.1 jmcneill }
192 1.1 jmcneill
193 1.8 uwe int
194 1.5 riz gpio_pin_map(void *gpio, int offset, u_int32_t mask, struct gpio_pinmap *map)
195 1.5 riz {
196 1.5 riz struct gpio_softc *sc = gpio;
197 1.5 riz int npins, pin, i;
198 1.5 riz
199 1.5 riz npins = gpio_npins(mask);
200 1.5 riz if (npins > sc->sc_npins)
201 1.5 riz return (1);
202 1.5 riz
203 1.5 riz for (npins = 0, i = 0; i < 32; i++)
204 1.5 riz if (mask & (1 << i)) {
205 1.5 riz pin = offset + i;
206 1.5 riz if (pin < 0 || pin >= sc->sc_npins)
207 1.5 riz return (1);
208 1.5 riz if (sc->sc_pins[pin].pin_mapped)
209 1.5 riz return (1);
210 1.5 riz sc->sc_pins[pin].pin_mapped = 1;
211 1.5 riz map->pm_map[npins++] = pin;
212 1.5 riz }
213 1.5 riz map->pm_size = npins;
214 1.5 riz
215 1.5 riz return (0);
216 1.5 riz }
217 1.5 riz
218 1.5 riz void
219 1.5 riz gpio_pin_unmap(void *gpio, struct gpio_pinmap *map)
220 1.5 riz {
221 1.5 riz struct gpio_softc *sc = gpio;
222 1.5 riz int pin, i;
223 1.5 riz
224 1.5 riz for (i = 0; i < map->pm_size; i++) {
225 1.5 riz pin = map->pm_map[i];
226 1.5 riz sc->sc_pins[pin].pin_mapped = 0;
227 1.5 riz }
228 1.5 riz }
229 1.5 riz
230 1.5 riz int
231 1.5 riz gpio_pin_read(void *gpio, struct gpio_pinmap *map, int pin)
232 1.5 riz {
233 1.5 riz struct gpio_softc *sc = gpio;
234 1.5 riz
235 1.5 riz return (gpiobus_pin_read(sc->sc_gc, map->pm_map[pin]));
236 1.5 riz }
237 1.5 riz
238 1.5 riz void
239 1.5 riz gpio_pin_write(void *gpio, struct gpio_pinmap *map, int pin, int value)
240 1.5 riz {
241 1.5 riz struct gpio_softc *sc = gpio;
242 1.5 riz
243 1.13 dyoung gpiobus_pin_write(sc->sc_gc, map->pm_map[pin], value);
244 1.13 dyoung sc->sc_pins[map->pm_map[pin]].pin_state = value;
245 1.5 riz }
246 1.5 riz
247 1.5 riz void
248 1.5 riz gpio_pin_ctl(void *gpio, struct gpio_pinmap *map, int pin, int flags)
249 1.5 riz {
250 1.5 riz struct gpio_softc *sc = gpio;
251 1.5 riz
252 1.5 riz return (gpiobus_pin_ctl(sc->sc_gc, map->pm_map[pin], flags));
253 1.5 riz }
254 1.5 riz
255 1.5 riz int
256 1.5 riz gpio_pin_caps(void *gpio, struct gpio_pinmap *map, int pin)
257 1.5 riz {
258 1.5 riz struct gpio_softc *sc = gpio;
259 1.5 riz
260 1.5 riz return (sc->sc_pins[map->pm_map[pin]].pin_caps);
261 1.5 riz }
262 1.5 riz
263 1.5 riz int
264 1.5 riz gpio_npins(u_int32_t mask)
265 1.5 riz {
266 1.5 riz int npins, i;
267 1.5 riz
268 1.5 riz for (npins = 0, i = 0; i < 32; i++)
269 1.5 riz if (mask & (1 << i))
270 1.5 riz npins++;
271 1.5 riz
272 1.5 riz return (npins);
273 1.5 riz }
274 1.5 riz
275 1.1 jmcneill int
276 1.11 christos gpioopen(dev_t dev, int flag, int mode,
277 1.11 christos struct lwp *l)
278 1.1 jmcneill {
279 1.1 jmcneill struct gpio_softc *sc;
280 1.16 cegger int ret;
281 1.1 jmcneill
282 1.17 cegger sc = device_lookup_private(&gpio_cd, minor(dev));
283 1.1 jmcneill if (sc == NULL)
284 1.1 jmcneill return (ENXIO);
285 1.1 jmcneill
286 1.1 jmcneill if (sc->sc_opened)
287 1.1 jmcneill return (EBUSY);
288 1.16 cegger
289 1.17 cegger if ((ret = gpiobus_open(sc->sc_gc, sc->sc_dev)))
290 1.16 cegger return ret;
291 1.16 cegger
292 1.1 jmcneill sc->sc_opened = 1;
293 1.1 jmcneill
294 1.1 jmcneill return (0);
295 1.1 jmcneill }
296 1.1 jmcneill
297 1.1 jmcneill int
298 1.11 christos gpioclose(dev_t dev, int flag, int mode,
299 1.11 christos struct lwp *l)
300 1.1 jmcneill {
301 1.1 jmcneill struct gpio_softc *sc;
302 1.1 jmcneill
303 1.17 cegger sc = device_lookup_private(&gpio_cd, minor(dev));
304 1.17 cegger gpiobus_close(sc->sc_gc, sc->sc_dev);
305 1.1 jmcneill sc->sc_opened = 0;
306 1.1 jmcneill
307 1.1 jmcneill return (0);
308 1.1 jmcneill }
309 1.1 jmcneill
310 1.1 jmcneill int
311 1.12 christos gpioioctl(dev_t dev, u_long cmd, void *data, int flag,
312 1.11 christos struct lwp *l)
313 1.1 jmcneill {
314 1.1 jmcneill struct gpio_softc *sc;
315 1.1 jmcneill gpio_chipset_tag_t gc;
316 1.1 jmcneill struct gpio_info *info;
317 1.1 jmcneill struct gpio_pin_op *op;
318 1.1 jmcneill struct gpio_pin_ctl *ctl;
319 1.1 jmcneill int pin, value, flags;
320 1.1 jmcneill
321 1.17 cegger sc = device_lookup_private(&gpio_cd, minor(dev));
322 1.1 jmcneill gc = sc->sc_gc;
323 1.1 jmcneill
324 1.17 cegger if (cmd != GPIOINFO && !device_is_active(sc->sc_dev))
325 1.13 dyoung return EBUSY;
326 1.13 dyoung
327 1.1 jmcneill switch (cmd) {
328 1.1 jmcneill case GPIOINFO:
329 1.1 jmcneill info = (struct gpio_info *)data;
330 1.1 jmcneill
331 1.1 jmcneill info->gpio_npins = sc->sc_npins;
332 1.1 jmcneill break;
333 1.1 jmcneill case GPIOPINREAD:
334 1.1 jmcneill op = (struct gpio_pin_op *)data;
335 1.1 jmcneill
336 1.1 jmcneill pin = op->gp_pin;
337 1.1 jmcneill if (pin < 0 || pin >= sc->sc_npins)
338 1.1 jmcneill return (EINVAL);
339 1.1 jmcneill
340 1.1 jmcneill /* return read value */
341 1.1 jmcneill op->gp_value = gpiobus_pin_read(gc, pin);
342 1.1 jmcneill break;
343 1.1 jmcneill case GPIOPINWRITE:
344 1.1 jmcneill op = (struct gpio_pin_op *)data;
345 1.1 jmcneill
346 1.1 jmcneill pin = op->gp_pin;
347 1.1 jmcneill if (pin < 0 || pin >= sc->sc_npins)
348 1.1 jmcneill return (EINVAL);
349 1.5 riz if (sc->sc_pins[pin].pin_mapped)
350 1.5 riz return (EBUSY);
351 1.1 jmcneill
352 1.1 jmcneill value = op->gp_value;
353 1.1 jmcneill if (value != GPIO_PIN_LOW && value != GPIO_PIN_HIGH)
354 1.1 jmcneill return (EINVAL);
355 1.1 jmcneill
356 1.1 jmcneill gpiobus_pin_write(gc, pin, value);
357 1.1 jmcneill /* return old value */
358 1.1 jmcneill op->gp_value = sc->sc_pins[pin].pin_state;
359 1.1 jmcneill /* update current value */
360 1.1 jmcneill sc->sc_pins[pin].pin_state = value;
361 1.1 jmcneill break;
362 1.1 jmcneill case GPIOPINTOGGLE:
363 1.1 jmcneill op = (struct gpio_pin_op *)data;
364 1.1 jmcneill
365 1.1 jmcneill pin = op->gp_pin;
366 1.1 jmcneill if (pin < 0 || pin >= sc->sc_npins)
367 1.1 jmcneill return (EINVAL);
368 1.5 riz if (sc->sc_pins[pin].pin_mapped)
369 1.5 riz return (EBUSY);
370 1.1 jmcneill
371 1.1 jmcneill value = (sc->sc_pins[pin].pin_state == GPIO_PIN_LOW ?
372 1.1 jmcneill GPIO_PIN_HIGH : GPIO_PIN_LOW);
373 1.1 jmcneill gpiobus_pin_write(gc, pin, value);
374 1.1 jmcneill /* return old value */
375 1.1 jmcneill op->gp_value = sc->sc_pins[pin].pin_state;
376 1.1 jmcneill /* update current value */
377 1.1 jmcneill sc->sc_pins[pin].pin_state = value;
378 1.1 jmcneill break;
379 1.1 jmcneill case GPIOPINCTL:
380 1.1 jmcneill ctl = (struct gpio_pin_ctl *)data;
381 1.1 jmcneill
382 1.1 jmcneill pin = ctl->gp_pin;
383 1.1 jmcneill if (pin < 0 || pin >= sc->sc_npins)
384 1.1 jmcneill return (EINVAL);
385 1.5 riz if (sc->sc_pins[pin].pin_mapped)
386 1.5 riz return (EBUSY);
387 1.1 jmcneill
388 1.1 jmcneill flags = ctl->gp_flags;
389 1.1 jmcneill /* check that the controller supports all requested flags */
390 1.1 jmcneill if ((flags & sc->sc_pins[pin].pin_caps) != flags)
391 1.1 jmcneill return (ENODEV);
392 1.1 jmcneill
393 1.1 jmcneill ctl->gp_caps = sc->sc_pins[pin].pin_caps;
394 1.1 jmcneill /* return old value */
395 1.1 jmcneill ctl->gp_flags = sc->sc_pins[pin].pin_flags;
396 1.1 jmcneill if (flags > 0) {
397 1.1 jmcneill gpiobus_pin_ctl(gc, pin, flags);
398 1.1 jmcneill /* update current value */
399 1.1 jmcneill sc->sc_pins[pin].pin_flags = flags;
400 1.1 jmcneill }
401 1.1 jmcneill break;
402 1.1 jmcneill default:
403 1.1 jmcneill return (ENOTTY);
404 1.1 jmcneill }
405 1.1 jmcneill
406 1.1 jmcneill return (0);
407 1.1 jmcneill }
408