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