gpioirq.c revision 1.2 1 /* $NetBSD: gpioirq.c,v 1.2 2023/11/06 00:35:05 brad Exp $ */
2
3 /*
4 * Copyright (c) 2016, 2023 Brad Spencer <brad (at) anduin.eldar.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: gpioirq.c,v 1.2 2023/11/06 00:35:05 brad Exp $");
21
22 /*
23 * GPIO driver that uses interrupts and can send that fact to userland.
24 */
25
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/device.h>
29 #include <sys/device_impl.h>
30 #include <sys/gpio.h>
31 #include <sys/module.h>
32 #include <sys/conf.h>
33 #include <sys/proc.h>
34 #include <sys/pool.h>
35 #include <sys/kmem.h>
36 #include <sys/condvar.h>
37
38 #include <dev/gpio/gpiovar.h>
39
40 #define GPIOIRQ_NPINS 64
41
42 struct gpioirq_iv {
43 char sc_intrstr[128];
44 void * sc_ih;
45 int i_thispin_index;
46 uint8_t i_thispin_num;
47 uint8_t i_parentunit;
48 struct gpioirq_softc *sc;
49 };
50
51 struct gpioirq_softc {
52 device_t sc_dev;
53 device_t sc_parentdev;
54 void * sc_gpio;
55 struct gpio_pinmap sc_map;
56 int _map[GPIOIRQ_NPINS];
57 struct gpioirq_iv sc_intrs[GPIOIRQ_NPINS];
58 int sc_npins;
59 kmutex_t sc_lock;
60 kmutex_t sc_read_mutex;
61 kmutex_t sc_dying_mutex;
62 bool sc_verbose;
63 bool sc_functional;
64 bool sc_opened;
65 bool sc_dying;
66 kcondvar_t sc_condreadready;
67 kcondvar_t sc_cond_dying;
68 pool_cache_t sc_readpool;
69 char *sc_readpoolname;
70 SIMPLEQ_HEAD(,gpioirq_read_q) sc_read_queue;
71 };
72
73 struct gpioirq_read_q {
74 int parentunit;
75 int thepin;
76 int theval;
77 SIMPLEQ_ENTRY(gpioirq_read_q) read_q;
78 };
79
80 #define GPIOIRQ_FLAGS_IRQMODE GPIO_INTR_MODE_MASK
81 #define GPIOIRQ_FLAGS_VERBOSE 0x1000
82
83 static int gpioirq_match(device_t, cfdata_t, void *);
84 static void gpioirq_attach(device_t, device_t, void *);
85 static int gpioirq_detach(device_t, int);
86 static int gpioirq_activate(device_t, enum devact);
87 static int gpioirq_intr(void *);
88 static uint8_t gpioirq_index_to_pin_num(struct gpioirq_softc *, int);
89 static uint8_t gpioirq_parent_unit(struct gpioirq_softc *);
90
91 CFATTACH_DECL_NEW(gpioirq, sizeof(struct gpioirq_softc),
92 gpioirq_match, gpioirq_attach,
93 gpioirq_detach, gpioirq_activate);
94
95 extern struct cfdriver gpioirq_cd;
96
97 static dev_type_open(gpioirq_open);
98 static dev_type_read(gpioirq_read);
99 static dev_type_close(gpioirq_close);
100 const struct cdevsw gpioirq_cdevsw = {
101 .d_open = gpioirq_open,
102 .d_close = gpioirq_close,
103 .d_read = gpioirq_read,
104 .d_write = nowrite,
105 .d_ioctl = noioctl,
106 .d_stop = nostop,
107 .d_tty = notty,
108 .d_poll = nopoll,
109 .d_mmap = nommap,
110 .d_kqfilter = nokqfilter,
111 .d_discard = nodiscard,
112 .d_flag = D_OTHER
113 };
114
115 static uint8_t
116 gpioirq_index_to_pin_num(struct gpioirq_softc *sc, int index)
117 {
118 return (uint8_t)gpio_pin_to_pin_num(sc->sc_gpio, &sc->sc_map, index);
119 }
120
121 static uint8_t
122 gpioirq_parent_unit(struct gpioirq_softc *sc)
123 {
124 device_t parent = sc->sc_parentdev;
125
126 return (uint8_t)parent->dv_unit;
127 }
128
129 static int
130 gpioirq_match(device_t parent, cfdata_t cf, void *aux)
131 {
132 struct gpio_attach_args *ga = aux;
133
134 if (strcmp(ga->ga_dvname, cf->cf_name))
135 return (0);
136
137 if (ga->ga_offset == -1)
138 return (0);
139
140 return (1);
141 }
142
143 static void
144 gpioirq_attach(device_t parent, device_t self, void *aux)
145 {
146 struct gpioirq_softc *sc = device_private(self);
147 struct gpio_attach_args *ga = aux;
148 int mask = ga->ga_mask;
149 int irqmode, flags;
150
151 sc->sc_dev = self;
152 sc->sc_parentdev = parent;
153 sc->sc_opened = false;
154 sc->sc_dying = false;
155 sc->sc_readpoolname = NULL;
156
157 /* Map pins */
158 sc->sc_gpio = ga->ga_gpio;
159 sc->sc_map.pm_map = sc->_map;
160
161 /* Determine our pin configuation. */
162 sc->sc_npins = gpio_npins(mask);
163 if (sc->sc_npins == 0) {
164 sc->sc_npins = 1;
165 mask = 0x1;
166 }
167
168 /* XXX - exit if more than allowed number of pins */
169
170 if (gpio_pin_map(sc->sc_gpio, ga->ga_offset,
171 mask, &sc->sc_map)) {
172 aprint_error(": can't map pins\n");
173 return;
174 }
175
176 aprint_normal("\n");
177
178 if (ga->ga_flags & GPIOIRQ_FLAGS_VERBOSE)
179 sc->sc_verbose = true;
180
181 irqmode = ga->ga_flags & GPIOIRQ_FLAGS_IRQMODE;
182
183 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
184 mutex_init(&sc->sc_dying_mutex, MUTEX_DEFAULT, IPL_VM);
185 mutex_init(&sc->sc_read_mutex, MUTEX_DEFAULT, IPL_VM);
186 cv_init(&sc->sc_cond_dying, "girqdie");
187 cv_init(&sc->sc_condreadready,"girqrr");
188 sc->sc_readpoolname = kmem_asprintf("girqread%d",device_unit(self));
189 sc->sc_readpool = pool_cache_init(sizeof(struct gpioirq_read_q),0,0,0,sc->sc_readpoolname,NULL,IPL_VM,NULL,NULL,NULL);
190 pool_cache_sethiwat(sc->sc_readpool,100);
191 SIMPLEQ_INIT(&sc->sc_read_queue);
192
193 for(int apin = 0; apin < sc->sc_npins; apin++) {
194 if (!gpio_intr_str(sc->sc_gpio, &sc->sc_map, apin, irqmode,
195 sc->sc_intrs[apin].sc_intrstr, sizeof(sc->sc_intrs[apin].sc_intrstr))) {
196 aprint_error_dev(self, "failed to decode interrupt\n");
197 return;
198 }
199
200 if (!gpio_pin_irqmode_issupported(sc->sc_gpio, &sc->sc_map, apin,
201 irqmode)) {
202 aprint_error_dev(self,
203 "irqmode not supported: %s\n", sc->sc_intrs[apin].sc_intrstr);
204 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
205 return;
206 }
207
208 flags = gpio_pin_get_conf(sc->sc_gpio, &sc->sc_map, apin);
209 flags = (flags & ~(GPIO_PIN_OUTPUT|GPIO_PIN_INOUT)) |
210 GPIO_PIN_INPUT;
211 if (!gpio_pin_set_conf(sc->sc_gpio, &sc->sc_map, apin, flags)) {
212 aprint_error_dev(sc->sc_dev, "pin not capable of input\n");
213 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
214 return;
215 }
216
217 /* These are static for each pin, so just stuff them in here,
218 * so they don't need to be looked up again.
219 */
220 sc->sc_intrs[apin].i_thispin_index = apin;
221 sc->sc_intrs[apin].i_thispin_num = gpioirq_index_to_pin_num(sc,apin);
222 sc->sc_intrs[apin].i_parentunit = gpioirq_parent_unit(sc);
223 sc->sc_intrs[apin].sc = sc;
224
225 sc->sc_intrs[apin].sc_ih = gpio_intr_establish(sc->sc_gpio, &sc->sc_map, apin, IPL_VM,
226 irqmode | GPIO_INTR_MPSAFE,
227 gpioirq_intr, &sc->sc_intrs[apin]);
228 if (sc->sc_intrs[apin].sc_ih == NULL) {
229 aprint_error_dev(self,
230 "unable to establish interrupt on %s\n", sc->sc_intrs[apin].sc_intrstr);
231 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
232 return;
233 }
234 aprint_normal_dev(self, "interrupting on %s\n", sc->sc_intrs[apin].sc_intrstr);
235 }
236
237 sc->sc_functional = true;
238 }
239
240 int
241 gpioirq_intr(void *arg)
242 {
243 struct gpioirq_iv *is = arg;
244 struct gpioirq_softc *sc = is->sc;
245 struct gpioirq_read_q *q;
246 int val;
247
248 mutex_enter(&sc->sc_lock);
249
250 val = gpio_pin_read(sc->sc_gpio, &sc->sc_map, is->i_thispin_index);
251
252 if (sc->sc_verbose)
253 printf("%s: interrupt on %s --> %d\n",
254 device_xname(sc->sc_dev), sc->sc_intrs[is->i_thispin_index].sc_intrstr, val);
255
256 mutex_exit(&sc->sc_lock);
257
258 if (sc->sc_opened) {
259 mutex_enter(&sc->sc_read_mutex);
260 q = pool_cache_get(sc->sc_readpool,PR_NOWAIT);
261 if (q != NULL) {
262 q->thepin = is->i_thispin_num;
263 q->parentunit = is->i_parentunit;
264 q->theval = val;
265 SIMPLEQ_INSERT_TAIL(&sc->sc_read_queue,q,read_q);
266 cv_signal(&sc->sc_condreadready);
267 } else {
268 aprint_error("Could not allocate memory for read pool\n");
269 }
270 mutex_exit(&sc->sc_read_mutex);
271 }
272
273 return (1);
274 }
275
276 static int
277 gpioirq_open(dev_t dev, int flags, int fmt, struct lwp *l)
278 {
279 struct gpioirq_softc *sc;
280
281 sc = device_lookup_private(&gpioirq_cd, minor(dev));
282 if (!sc)
283 return (ENXIO);
284
285 if (sc->sc_opened)
286 return (EBUSY);
287
288 mutex_enter(&sc->sc_lock);
289 sc->sc_opened = true;
290 mutex_exit(&sc->sc_lock);
291
292 return (0);
293 }
294
295 static int
296 gpioirq_read(dev_t dev, struct uio *uio, int flags)
297 {
298 struct gpioirq_softc *sc;
299 struct gpioirq_read_q *chp;
300 int error = 0,any;
301 uint8_t obuf[3];
302
303 sc = device_lookup_private(&gpioirq_cd, minor(dev));
304 if (!sc)
305 return (ENXIO);
306
307 while (uio->uio_resid > 0) {
308 any = 0;
309 error = 0;
310 mutex_enter(&sc->sc_read_mutex);
311
312 while (any == 0) {
313 chp = SIMPLEQ_FIRST(&sc->sc_read_queue);
314 if (chp != NULL) {
315 SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
316 any = 1;
317 break;
318 } else {
319 error = cv_wait_sig(&sc->sc_condreadready,&sc->sc_read_mutex);
320 if (sc->sc_dying)
321 error = EIO;
322 if (error == 0)
323 continue;
324 break;
325 }
326 }
327
328 if (any == 1 && error == 0) {
329 obuf[0] = (uint8_t)chp->parentunit;
330 obuf[1] = (uint8_t)chp->thepin;
331 obuf[2] = (uint8_t)chp->theval;
332 pool_cache_put(sc->sc_readpool,chp);
333 mutex_exit(&sc->sc_read_mutex);
334 if ((error = uiomove(&obuf[0], 3, uio)) != 0) {
335 break;
336 }
337 } else {
338 mutex_exit(&sc->sc_read_mutex);
339 if (error) {
340 break;
341 }
342 }
343 }
344
345 if (sc->sc_dying) {
346 mutex_enter(&sc->sc_dying_mutex);
347 cv_signal(&sc->sc_cond_dying);
348 mutex_exit(&sc->sc_dying_mutex);
349 }
350 return error;
351 }
352
353 static int
354 gpioirq_close(dev_t dev, int flags, int fmt, struct lwp *l)
355 {
356 struct gpioirq_softc *sc;
357 struct gpioirq_read_q *q;
358
359 sc = device_lookup_private(&gpioirq_cd, minor(dev));
360
361 mutex_enter(&sc->sc_lock);
362 while ((q = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) {
363 SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
364 pool_cache_put(sc->sc_readpool,q);
365 }
366 sc->sc_opened = false;
367 mutex_exit(&sc->sc_lock);
368
369 return(0);
370 }
371
372 int
373 gpioirq_detach(device_t self, int flags)
374 {
375 struct gpioirq_softc *sc = device_private(self);
376 struct gpioirq_read_q *q;
377
378 /* Clear the handler and disable the interrupt. */
379 for(int apin = 0;apin < sc->sc_npins;apin++) {
380 gpio_intr_disestablish(sc->sc_gpio, sc->sc_intrs[apin].sc_ih);
381 }
382
383 /* Release the pin. */
384 gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
385
386 sc->sc_dying = true;
387
388 if (sc->sc_opened) {
389 mutex_enter(&sc->sc_dying_mutex);
390 mutex_enter(&sc->sc_read_mutex);
391 cv_signal(&sc->sc_condreadready);
392 mutex_exit(&sc->sc_read_mutex);
393 /* In the worst case this will time out after 5 seconds.
394 * It really should not take that long for the drain / whatever
395 * to happen
396 */
397 cv_timedwait_sig(&sc->sc_cond_dying,
398 &sc->sc_dying_mutex, mstohz(5000));
399 mutex_exit(&sc->sc_dying_mutex);
400 cv_destroy(&sc->sc_condreadready);
401 cv_destroy(&sc->sc_cond_dying);
402 }
403
404 /* Drain any read pools */
405 while ((q = SIMPLEQ_FIRST(&sc->sc_read_queue)) != NULL) {
406 SIMPLEQ_REMOVE_HEAD(&sc->sc_read_queue, read_q);
407 pool_cache_put(sc->sc_readpool,q);
408 }
409
410 if (sc->sc_readpoolname != NULL) {
411 kmem_free(sc->sc_readpoolname,strlen(sc->sc_readpoolname) + 1);
412 }
413
414 mutex_destroy(&sc->sc_read_mutex);
415 mutex_destroy(&sc->sc_lock);
416
417 return (0);
418 }
419
420 int
421 gpioirq_activate(device_t self, enum devact act)
422 {
423
424 struct gpioirq_softc *sc = device_private(self);
425
426 switch (act) {
427 case DVACT_DEACTIVATE:
428 sc->sc_dying = true;
429 return (0);
430 default:
431 return (EOPNOTSUPP);
432 }
433 }
434
435 MODULE(MODULE_CLASS_DRIVER, gpioirq, "gpio");
436
437 #ifdef _MODULE
438 #include "ioconf.c"
439 #endif
440
441 static int
442 gpioirq_modcmd(modcmd_t cmd, void *opaque)
443 {
444 int error = 0;
445 #ifdef _MODULE
446 int bmaj = -1, cmaj = -1;
447 #endif
448
449 switch (cmd) {
450 case MODULE_CMD_INIT:
451 #ifdef _MODULE
452 error = config_init_component(cfdriver_ioconf_gpioirq,
453 cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq);
454 if (error) {
455 aprint_error("%s: unable to init component\n",
456 gpioirq_cd.cd_name);
457 return (error);
458 }
459
460 error = devsw_attach("gpioirq", NULL, &bmaj,
461 &gpioirq_cdevsw, &cmaj);
462 if (error) {
463 aprint_error("%s: unable to attach devsw\n",
464 gpioirq_cd.cd_name);
465 config_fini_component(cfdriver_ioconf_gpioirq,
466 cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq);
467 }
468 #endif
469 return (error);
470 case MODULE_CMD_FINI:
471 #ifdef _MODULE
472 devsw_detach(NULL, &gpioirq_cdevsw);
473 config_fini_component(cfdriver_ioconf_gpioirq,
474 cfattach_ioconf_gpioirq, cfdata_ioconf_gpioirq);
475 #endif
476 return (0);
477 default:
478 return (ENOTTY);
479 }
480 }
481