Home | History | Annotate | Line # | Download | only in gpio
      1 /* $NetBSD: gpiopps.c,v 1.5 2023/06/24 05:34:59 msaitoh Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2016 Brad Spencer <brad (at) anduin.eldar.org>
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions, and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: gpiopps.c,v 1.5 2023/06/24 05:34:59 msaitoh Exp $");
     30 
     31 /*
     32  * GPIO interface to the pps subsystem for ntp support.
     33  */
     34 
     35 #include <sys/param.h>
     36 #include <sys/systm.h>
     37 #include <sys/bitops.h>
     38 #include <sys/device.h>
     39 #include <sys/module.h>
     40 #include <sys/conf.h>
     41 #include <sys/proc.h>
     42 #include <sys/ioctl.h>
     43 #include <sys/timepps.h>
     44 
     45 #include <sys/gpio.h>
     46 #include <dev/gpio/gpiovar.h>
     47 
     48 #define	GPIOPPS_NPINS		2
     49 
     50 struct gpiopps_softc {
     51 	device_t		sc_dev;
     52 	void *			sc_gpio;
     53 	struct gpio_pinmap	sc_map;
     54 	int			_map[GPIOPPS_NPINS];
     55 	struct {
     56 		char		sc_intrstr[128];
     57 		void *		sc_ih;
     58 		int		sc_irqmode;
     59 	} sc_intrs[GPIOPPS_NPINS];
     60 	int			sc_assert_val;
     61 	int			sc_npins;
     62 	struct pps_state	sc_pps_state;
     63 	bool			sc_functional;
     64 	bool			sc_busy;
     65 };
     66 
     67 #define	GPIOPPS_FLAGS_ASSERT_NEG_EDGE	0x01
     68 #define	GPIOPPS_FLAGS_NO_DOUBLE_EDGE	0x02
     69 
     70 static int	gpiopps_match(device_t, cfdata_t, void *);
     71 static void	gpiopps_attach(device_t, device_t, void *);
     72 static int	gpiopps_detach(device_t, int);
     73 
     74 CFATTACH_DECL_NEW(gpiopps, sizeof(struct gpiopps_softc),
     75 		  gpiopps_match, gpiopps_attach,
     76 		  gpiopps_detach, NULL /*activate*/);
     77 
     78 extern struct cfdriver gpiopps_cd;
     79 
     80 static dev_type_open(gpioppsopen);
     81 static dev_type_close(gpioppsclose);
     82 static dev_type_ioctl(gpioppsioctl);
     83 const struct cdevsw gpiopps_cdevsw = {
     84 	.d_open = gpioppsopen,
     85 	.d_close = gpioppsclose,
     86 	.d_read = noread,
     87 	.d_write = nowrite,
     88 	.d_ioctl = gpioppsioctl,
     89 	.d_stop = nostop,
     90 	.d_tty = notty,
     91 	.d_poll = nopoll,
     92 	.d_mmap = nommap,
     93 	.d_kqfilter = nokqfilter,
     94 	.d_discard = nodiscard,
     95 	.d_flag = D_OTHER
     96 };
     97 
     98 static int
     99 gpiopps_match(device_t parent, cfdata_t cf, void *aux)
    100 {
    101 	struct gpio_attach_args *ga = aux;
    102 	int bits;
    103 
    104 	if (strcmp(ga->ga_dvname, cf->cf_name))
    105 		return (0);
    106 
    107 	if (ga->ga_offset == -1)
    108 		return (0);
    109 
    110 	/* One or 2 pins (unspecified, assume 1) */
    111 	bits = gpio_npins(ga->ga_mask);
    112 	if (bits > 2)
    113 		return (0);
    114 
    115 	return (1);
    116 }
    117 
    118 static void
    119 gpiopps_attach(device_t parent, device_t self, void *aux)
    120 {
    121 	struct gpiopps_softc *sc = device_private(self);
    122 	struct gpio_attach_args *ga = aux;
    123 	int flags, intrcaps, npins;
    124 	int assert_edge = GPIO_INTR_POS_EDGE;
    125 	int clear_edge  = GPIO_INTR_NEG_EDGE;
    126 	int mask = ga->ga_mask;
    127 
    128 	sc->sc_dev = self;
    129 	sc->sc_assert_val = GPIO_PIN_HIGH;
    130 
    131 	/* Map pins */
    132 	sc->sc_gpio = ga->ga_gpio;
    133 	sc->sc_map.pm_map = sc->_map;
    134 
    135 	/* Determine our pin configuration. */
    136 	npins = gpio_npins(mask);
    137 	if (npins == 0) {
    138 		npins = 1;
    139 		mask = 0x1;
    140 	}
    141 
    142 	/*
    143 	 * Here's the different pin configurations we handle:
    144 	 *
    145 	 * 1 pin, single-edge capable pin -- interrupt on single-edge,
    146 	 * only trigger ASSERT signal.
    147 	 *
    148 	 * 1 pin, double-edge capable pin -- interrupt on double-edge,
    149 	 * trigger ASSERT and CLEAR signals, unless 0x2 is set in ga_flags,
    150 	 * in which case we degrade to ASSERT only.
    151 	 *
    152 	 * 2 pins -- pin #0 is ASSERT signal, pin #1 is CLEAR signal.
    153 	 *
    154 	 * If 0x1 is set in ga_flags, ASSERT is negative edge, otherwise
    155 	 * assert is positive edge.
    156 	 */
    157 	if (npins < 1 || npins > 2) {
    158 		aprint_error(": invalid pin configuration\n");
    159 		return;
    160 	}
    161 	if (ga->ga_flags & GPIOPPS_FLAGS_ASSERT_NEG_EDGE) {
    162 		assert_edge = GPIO_INTR_NEG_EDGE;
    163 		clear_edge  = GPIO_INTR_POS_EDGE;
    164 		sc->sc_assert_val = GPIO_PIN_LOW;
    165 	}
    166 
    167 	if (gpio_pin_map(sc->sc_gpio, ga->ga_offset, mask,
    168 			 &sc->sc_map)) {
    169 		aprint_error(": can't map pins\n");
    170 		return;
    171 	}
    172 	sc->sc_npins = npins;
    173 
    174 	aprint_normal("\n");
    175 
    176 	if (sc->sc_npins == 2) {
    177 		intrcaps = gpio_pin_intrcaps(sc->sc_gpio, &sc->sc_map, 0);
    178 		if ((intrcaps & assert_edge) == 0) {
    179 			aprint_error_dev(sc->sc_dev,
    180 			    "%s edge interrupt not supported for ASSERT\n",
    181 			    assert_edge == GPIO_INTR_POS_EDGE ? "positive"
    182 			    				      : "negative");
    183 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    184 			return;
    185 		}
    186 		sc->sc_intrs[0].sc_irqmode = assert_edge;
    187 		if (!gpio_intr_str(sc->sc_gpio, &sc->sc_map, 0,
    188 				   sc->sc_intrs[0].sc_irqmode,
    189 				   sc->sc_intrs[0].sc_intrstr,
    190 				   sizeof(sc->sc_intrs[0].sc_intrstr))) {
    191 			aprint_error_dev(self,
    192 			    "failed to decode ASSERT interrupt\n");
    193 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    194 			return;
    195 		}
    196 		flags = gpio_pin_get_conf(sc->sc_gpio, &sc->sc_map, 0);
    197 		flags = (flags & ~(GPIO_PIN_OUTPUT|GPIO_PIN_INOUT)) |
    198 		    GPIO_PIN_INPUT;
    199 		if (!gpio_pin_set_conf(sc->sc_gpio, &sc->sc_map, 0, flags)) {
    200 			aprint_error_dev(sc->sc_dev,
    201 			    "ASSERT pin not capable of input\n");
    202 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    203 			return;
    204 		}
    205 
    206 		intrcaps = gpio_pin_intrcaps(sc->sc_gpio, &sc->sc_map, 1);
    207 		if ((intrcaps & clear_edge) == 0) {
    208 			aprint_error_dev(sc->sc_dev,
    209 			    "%s edge interrupt not supported for CLEAR\n",
    210 			    clear_edge == GPIO_INTR_POS_EDGE ? "positive"
    211 			    				     : "negative");
    212 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    213 			return;
    214 		}
    215 		sc->sc_intrs[1].sc_irqmode = clear_edge;
    216 		if (!gpio_intr_str(sc->sc_gpio, &sc->sc_map, 1,
    217 				   sc->sc_intrs[1].sc_irqmode,
    218 				   sc->sc_intrs[1].sc_intrstr,
    219 				   sizeof(sc->sc_intrs[1].sc_intrstr))) {
    220 			aprint_error_dev(self,
    221 			    "failed to decode CLEAR interrupt\n");
    222 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    223 			return;
    224 		}
    225 		flags = gpio_pin_get_conf(sc->sc_gpio, &sc->sc_map, 1);
    226 		flags = (flags & ~(GPIO_PIN_OUTPUT|GPIO_PIN_INOUT)) |
    227 		    GPIO_PIN_INPUT;
    228 		if (!gpio_pin_set_conf(sc->sc_gpio, &sc->sc_map, 1, flags)) {
    229 			aprint_error_dev(sc->sc_dev,
    230 			    "CLEAR pin not capable of input\n");
    231 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    232 			return;
    233 		}
    234 
    235 		aprint_normal_dev(self, "ASSERT interrupting on %s\n",
    236 				  sc->sc_intrs[0].sc_intrstr);
    237 		aprint_normal_dev(self, "CLEAR interrupting on %s\n",
    238 				  sc->sc_intrs[1].sc_intrstr);
    239 	} else {
    240 		intrcaps = gpio_pin_intrcaps(sc->sc_gpio, &sc->sc_map, 0);
    241 		bool double_edge = false;
    242 		if ((intrcaps & GPIO_INTR_DOUBLE_EDGE) &&
    243 		    (ga->ga_flags & GPIOPPS_FLAGS_NO_DOUBLE_EDGE) == 0) {
    244 			sc->sc_intrs[0].sc_irqmode = GPIO_INTR_DOUBLE_EDGE;
    245 			double_edge = true;
    246 		} else if (intrcaps & assert_edge) {
    247 			sc->sc_intrs[0].sc_irqmode = assert_edge;
    248 		} else {
    249 			aprint_error_dev(sc->sc_dev,
    250 			    "%s edge interrupt not supported for ASSERT\n",
    251 			    assert_edge == GPIO_INTR_POS_EDGE ? "positive"
    252 			    				      : "negative");
    253 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    254 			return;
    255 		}
    256 		if (!gpio_intr_str(sc->sc_gpio, &sc->sc_map, 0,
    257 				   sc->sc_intrs[0].sc_irqmode,
    258 				   sc->sc_intrs[0].sc_intrstr,
    259 				   sizeof(sc->sc_intrs[0].sc_intrstr))) {
    260 			aprint_error_dev(self,
    261 			    "failed to decode interrupt\n");
    262 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    263 			return;
    264 		}
    265 		flags = gpio_pin_get_conf(sc->sc_gpio, &sc->sc_map, 0);
    266 		flags = (flags & ~(GPIO_PIN_OUTPUT|GPIO_PIN_INOUT)) |
    267 		    GPIO_PIN_INPUT;
    268 		if (!gpio_pin_set_conf(sc->sc_gpio, &sc->sc_map, 0, flags)) {
    269 			aprint_error_dev(sc->sc_dev,
    270 			    "ASSERT%s pin not capable of input\n",
    271 			    double_edge ? "+CLEAR" : "");
    272 			gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    273 			return;
    274 		}
    275 
    276 		aprint_normal_dev(self, "ASSERT%s interrupting on %s\n",
    277 				  double_edge ? "+CLEAR" : "",
    278 				  sc->sc_intrs[0].sc_intrstr);
    279 	}
    280 
    281 	/* Interrupt will be registered when device is opened for use. */
    282 
    283 	sc->sc_functional = true;
    284 }
    285 
    286 static int
    287 gpiopps_assert_intr(void *arg)
    288 {
    289 	struct gpiopps_softc *sc = arg;
    290 
    291 	mutex_spin_enter(&timecounter_lock);
    292 	pps_capture(&sc->sc_pps_state);
    293 	pps_event(&sc->sc_pps_state, PPS_CAPTUREASSERT);
    294 	mutex_spin_exit(&timecounter_lock);
    295 
    296 	return (1);
    297 }
    298 
    299 static int
    300 gpiopps_clear_intr(void *arg)
    301 {
    302 	struct gpiopps_softc *sc = arg;
    303 
    304 	mutex_spin_enter(&timecounter_lock);
    305 	pps_capture(&sc->sc_pps_state);
    306 	pps_event(&sc->sc_pps_state, PPS_CAPTURECLEAR);
    307 	mutex_spin_exit(&timecounter_lock);
    308 
    309 	return (1);
    310 }
    311 
    312 static int
    313 gpiopps_double_intr(void *arg)
    314 {
    315 	struct gpiopps_softc *sc = arg;
    316 	int val = gpio_pin_read(sc->sc_gpio, &sc->sc_map, 0);
    317 
    318 	if (val == sc->sc_assert_val)
    319 		return (gpiopps_assert_intr(arg));
    320 	return (gpiopps_clear_intr(arg));
    321 }
    322 
    323 static void
    324 gpiopps_disable_interrupts(struct gpiopps_softc *sc)
    325 {
    326 	int i;
    327 
    328 	for (i = 0; i < GPIOPPS_NPINS; i++) {
    329 		if (sc->sc_intrs[i].sc_ih != NULL) {
    330 			gpio_intr_disestablish(sc->sc_gpio,
    331 					       sc->sc_intrs[i].sc_ih);
    332 			sc->sc_intrs[i].sc_ih = NULL;
    333 		}
    334 	}
    335 }
    336 
    337 static void
    338 gpiopps_reset(struct gpiopps_softc *sc)
    339 {
    340 	mutex_spin_enter(&timecounter_lock);
    341 	sc->sc_pps_state.ppsparam.mode = 0;
    342 	sc->sc_busy = false;
    343 	mutex_spin_exit(&timecounter_lock);
    344 }
    345 
    346 static int
    347 gpiopps_detach(device_t self, int flags)
    348 {
    349 	struct gpiopps_softc *sc = device_private(self);
    350 
    351 	if (!sc->sc_functional) {
    352 		/* Attach failed, no work to do; resources already released. */
    353 		return (0);
    354 	}
    355 
    356 	if (sc->sc_busy)
    357 		return (EBUSY);
    358 
    359 	/*
    360 	 * Clear the handler and disable the interrupt.
    361 	 * NOTE: This should never be true, because we
    362 	 * register the interrupt handler at open, and
    363 	 * remove it at close.  We keep this as a backstop.
    364 	 */
    365 	gpiopps_disable_interrupts(sc);
    366 
    367 	/* Release the pin. */
    368 	gpio_pin_unmap(sc->sc_gpio, &sc->sc_map);
    369 
    370 	return (0);
    371 }
    372 
    373 static int
    374 gpioppsopen(dev_t dev, int flags, int fmt, struct lwp *l)
    375 {
    376 	struct gpiopps_softc *sc;
    377 	int error = EIO;
    378 
    379 	sc = device_lookup_private(&gpiopps_cd, minor(dev));
    380 	if (sc == NULL)
    381 		return (ENXIO);
    382 
    383 	if (!sc->sc_functional)
    384 		return (EIO);
    385 
    386 	mutex_spin_enter(&timecounter_lock);
    387 
    388 	if (sc->sc_busy) {
    389 		mutex_spin_exit(&timecounter_lock);
    390 		return (0);
    391 	}
    392 
    393 	memset(&sc->sc_pps_state, 0, sizeof(sc->sc_pps_state));
    394 	sc->sc_pps_state.ppscap = PPS_CAPTUREASSERT;
    395 	if (sc->sc_npins == 2 ||
    396 	    sc->sc_intrs[0].sc_irqmode == GPIO_INTR_DOUBLE_EDGE)
    397 	    	sc->sc_pps_state.ppscap |= PPS_CAPTURECLEAR;
    398 	pps_init(&sc->sc_pps_state);
    399 	sc->sc_busy = true;
    400 
    401 	mutex_spin_exit(&timecounter_lock);
    402 
    403 	if (sc->sc_npins == 2) {
    404 		sc->sc_intrs[0].sc_ih = gpio_intr_establish(sc->sc_gpio,
    405 		    &sc->sc_map, 0, IPL_VM,
    406 		    sc->sc_intrs[0].sc_irqmode | GPIO_INTR_MPSAFE,
    407 		    gpiopps_assert_intr, sc);
    408 		if (sc->sc_intrs[0].sc_ih == NULL) {
    409 			aprint_error_dev(sc->sc_dev,
    410 			    "unable to establish ASSERT interrupt on %s\n",
    411 			    sc->sc_intrs[0].sc_intrstr);
    412 			goto out;
    413 		}
    414 
    415 		sc->sc_intrs[1].sc_ih = gpio_intr_establish(sc->sc_gpio,
    416 		    &sc->sc_map, 1, IPL_VM,
    417 		    sc->sc_intrs[1].sc_irqmode | GPIO_INTR_MPSAFE,
    418 		    gpiopps_clear_intr, sc);
    419 		if (sc->sc_intrs[1].sc_ih == NULL) {
    420 			aprint_error_dev(sc->sc_dev,
    421 			    "unable to establish CLEAR interrupt on %s\n",
    422 			    sc->sc_intrs[0].sc_intrstr);
    423 			gpio_intr_disestablish(sc->sc_gpio,
    424 					       sc->sc_intrs[0].sc_ih);
    425 			goto out;
    426 		}
    427 	} else {
    428 		bool double_edge =
    429 		    sc->sc_intrs[0].sc_irqmode == GPIO_INTR_DOUBLE_EDGE;
    430 		sc->sc_intrs[0].sc_ih = gpio_intr_establish(sc->sc_gpio,
    431 		    &sc->sc_map, 0, IPL_VM,
    432 		    sc->sc_intrs[0].sc_irqmode | GPIO_INTR_MPSAFE,
    433 		    double_edge ? gpiopps_double_intr
    434 				: gpiopps_assert_intr, sc);
    435 		if (sc->sc_intrs[0].sc_ih == NULL) {
    436 			aprint_error_dev(sc->sc_dev,
    437 			    "unable to establish ASSERT%s interrupt on %s\n",
    438 			    double_edge ? "+CLEAR" : "",
    439 			    sc->sc_intrs[0].sc_intrstr);
    440 			goto out;
    441 		}
    442 	}
    443 
    444 	error = 0;
    445 
    446  out:
    447 	if (error) {
    448 		gpiopps_disable_interrupts(sc);
    449 		gpiopps_reset(sc);
    450 	}
    451 	return (error);
    452 }
    453 
    454 static int
    455 gpioppsclose(dev_t dev, int flags, int fmt, struct lwp *l)
    456 {
    457 	struct gpiopps_softc *sc;
    458 
    459 	sc = device_lookup_private(&gpiopps_cd, minor(dev));
    460 
    461 	gpiopps_disable_interrupts(sc);
    462 	gpiopps_reset(sc);
    463 
    464 	return (0);
    465 }
    466 
    467 static int
    468 gpioppsioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
    469 {
    470 	struct gpiopps_softc *sc;
    471 	int error = 0;
    472 
    473 	sc = device_lookup_private(&gpiopps_cd, minor(dev));
    474 
    475 	switch (cmd) {
    476 	case PPS_IOC_CREATE:
    477 	case PPS_IOC_DESTROY:
    478 	case PPS_IOC_GETPARAMS:
    479 	case PPS_IOC_SETPARAMS:
    480 	case PPS_IOC_GETCAP:
    481 	case PPS_IOC_FETCH:
    482 	case PPS_IOC_KCBIND:
    483 		mutex_spin_enter(&timecounter_lock);
    484 		error = pps_ioctl(cmd, data, &sc->sc_pps_state);
    485 		mutex_spin_exit(&timecounter_lock);
    486 		break;
    487 
    488 	default:
    489 		error = EPASSTHROUGH;
    490 	}
    491 
    492 	return (error);
    493 }
    494 
    495 MODULE(MODULE_CLASS_DRIVER, gpiopps, "gpio");
    496 
    497 #ifdef _MODULE
    498 #include "ioconf.c"
    499 #endif
    500 
    501 static int
    502 gpiopps_modcmd(modcmd_t cmd, void *opaque)
    503 {
    504 	int error = 0;
    505 #ifdef _MODULE
    506 	int bmaj = -1, cmaj = -1;
    507 #endif
    508 
    509 	switch (cmd) {
    510 	case MODULE_CMD_INIT:
    511 #ifdef _MODULE
    512 		error = devsw_attach("gpiopps", NULL, &bmaj,
    513 		    &gpiopps_cdevsw, &cmaj);
    514 		if (error) {
    515 			aprint_error("%s: unable to attach devsw\n",
    516 			    gpiopps_cd.cd_name);
    517 			return error;
    518 		}
    519 		error = config_init_component(cfdriver_ioconf_gpiopps,
    520 		    cfattach_ioconf_gpiopps, cfdata_ioconf_gpiopps);
    521 		if (error) {
    522 			aprint_error("%s: unable to init component\n",
    523 			    gpiopps_cd.cd_name);
    524 			devsw_detach(NULL, &gpiopps_cdevsw);
    525 			return (error);
    526 		}
    527 #endif
    528 		return (error);
    529 	case MODULE_CMD_FINI:
    530 #ifdef _MODULE
    531 		config_fini_component(cfdriver_ioconf_gpiopps,
    532 		    cfattach_ioconf_gpiopps, cfdata_ioconf_gpiopps);
    533 		devsw_detach(NULL, &gpiopps_cdevsw);
    534 #endif
    535 		return (0);
    536 	default:
    537 		return (ENOTTY);
    538 	}
    539 }
    540