Re: GPIO subsystem and interrupts -- no way to do rising & falling edge on same pin?

Jason Thorpe <[email protected]> Tue, 15 May 2018 17:22:26 -0400
Newsgroups gmane.os.netbsd.devel.embedded
Message-ID <[email protected]>

> On May 15, 2018, at 7:17 AM, Jason Thorpe <[email protected]> wrote:
>=20
> I=E2=80=99ve done this =E2=80=94 I=E2=80=99m going to be posting some =
more on this as soon as I=E2=80=99ve tested it (and had Brad Spencer =
verify that the PPS driver he submitted still works correctly with the =
new way).

Ok, well, testing is still pending, but I figured I=E2=80=99m stuck on a =
plane and have some time so might as well post about what the new =
interface looks like.

The following have been added to gpio_chipset_tag_t:

        void *  (*gp_intr_establish)(void *, int, int, int,
                                     int (*)(void *), void *);
        void    (*gp_intr_disestablish)(void *, void *);
        bool    (*gp_intr_str)(void *, int, int, char *, size_t);

A back-end would initialize them with pointers to functions such as =
these:

static void *
bcmgpio_gpio_intr_establish(void *vsc, int pin, int ipl, int irqmode,
                            int (*func)(void *), void *arg);

static void
bcmgpio_gpio_intr_disestablish(void *vsc, void *ih);

static bool
bcmgpio_gpio_intrstr(void *vsc, int pin, int irqmode, char *buf, size_t =
buflen);

The gpio_pin structure no longer has pin_callback or pin_callback_arg =
fields.  The following fields have been added (filled in by the =
back-end).

	int			pin_intrcaps;	/* interrupt =
capabilities */

gpio_pin_ctl_intr() has been removed, as has gpio_intr() and =
gpio_pin_irqen().  Instead, we have:

void *	gpio_intr_establish(void *, struct gpio_pinmap *, int, int, int,
			    int (*)(void *), void *);
void	gpio_intr_disestablish(void *, void *);
bool	gpio_intr_str(void *, struct gpio_pinmap *, int, int,
		      char *, size_t);

Interrupts will be dispatched by the back-end GPIO controller driver, as =
they are with FDT-registered interrupts.  This allows the GPIO code to =
support level-triggered interrupts, among other things.

A new gpio_pin_intrcaps() has been added, which is like gpio_pin_caps(), =
but it returns the interrupt capabilities instead.

gpio_pin_get_conf() and gpio_pin_set_conf() have been added; =
gpio_pin_set_conf() is like gpio_pin_ctl(), but it checks the requested =
mode against the capabilities of the pin.  gpio_pin_get_conf() returns =
the currently set mode.

There is also a new gpio_pin_irqmode_issupported(), which, in addition =
to checking against pin capabilities, checks for non-sensical interrupt =
mode combinations.

The old GPIO pin mode flags GPIO_PIN_EVENTS, GPIO_PIN_LEVEL, and =
GPIO_PIN_FALLING have been removed and are now available for recycling.

There are new, separate GPIO interrupt flags:

/* GPIO interrupt flags */
#define GPIO_INTR_POS_EDGE      0x00000001      /* interrupt on rising =
edge */
#define GPIO_INTR_NEG_EDGE      0x00000002      /* interrupt on falling =
edge */
#define GPIO_INTR_DOUBLE_EDGE   0x00000004      /* interrupt on both =
edges */
#define GPIO_INTR_HIGH_LEVEL    0x00000008      /* interrupt on high =
level */
#define GPIO_INTR_LOW_LEVEL     0x00000010      /* interrupt on low =
level */
#define GPIO_INTR_MPSAFE        0x80000000      /* MP-safe handling */

These are expressive enough to describe the capabilities of modern GPIO =
controllers, and the modes (EDGE and LEVEL bits) are generally treated =
as mutually exclusive, although if you request a POS_EDGE and a NEG_EDGE =
interrupt together, the code will internally map that to DOUBLE_EDGE =
before checking for that capability on the pin.

This doesn=E2=80=99t change any of the API for userland at all; none of =
the interrupt bits were useful to userland before, and nothing in the =
tree used them at all.

Here=E2=80=99s a link to the GPIO infrastructure diffs, with the bcm2835 =
back-end changes to support both FDT and GPIO interrupt interfaces.

	=
https://www.dropbox.com/s/zlmi8ang9gje6ld/gpio-diffs-20180515.txt

Tip o=E2=80=99 the hat to Brad Spencer for his initial work on =
supporting GPIO interrupts on Raspberry Pi.  Once the infrastructure =
changes are in, I intend to integrate his =E2=80=9Cgpioiorq=E2=80=9D =
sample driver, =E2=80=9Cgpiopps=E2=80=9D NTP PPS driver, and =
=E2=80=9Cgpiorng=E2=80=9D radioactive-decay random number generator =
driver (all modified to work with the new GPIO interrupt =
infrastructure).

At some future juncture, it would be awfully nice if the FDT and the =
GPIO interrupt interfaces were fully harmonized.  But for now, this is a =
big improvement and will support stuff like Brad=E2=80=99s nifty =
hardware hacks (you guys should really read his web pages - good stuff!) =
as well as my silly little clock project.

Feedback appreciated.

Thx.

-- thorpej
   (Gosh, it=E2=80=99s fun to be properly hacking on NetBSD again=E2=80=A6=
)