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