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