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