External interrupts

This is not meant to be comprehensive guide about the external interrupts (EINT0..EINT31), just some notes in getting them to work with the 3.19 stock kernel.

Pin support
Not all pins are available for handling of edges and interrupts. For example, on Cubieboard with the 3.4.x kernel there are only 6 pins: ph14, ph15, pi11, pi13, pi10, pi12. And it can't be changed via settings in fex file.

The following information was extracted from mainline Linux kernel sources (drivers/pinctrl/sunxi):

A10
External interrupts on PH0..PH21, PI10..PI19

A10s
External interrupts on PG0..PG13, PE0..PE1, PB2..PB14, PB19..PB20, PA17

A13
External interrupts on PG0..PG4, PG10..PG12, PE0..PE1, PB2..PB4, PB10

A31
External interrupts on PA, PB, PE, PG, PL5..PL8, PM0..PM7

A20
External interrupts on PC19..PC22, PH0..PH21, PI10..PI19

A23
External interrupts on PB, PG, PL

A33
External interrupts on PB, PG, PL

A83t
External interrupts on PB, PG, PH

A80
External interrupts on PA, PB, PE, PG, PH8..PH18

The Setup
I have three interrupt inputs that were used on the linux-sunxi-3.4.102 kernel that needed to be ported onto the recent 3.19 kernel. As you may know, the 3.4.102 uses the FEX files, and direct bit-banging to get things configured. The 3.19 kernel uses the device tree (dts) files to describe the hardware. Yes, you can still bang hardware, but I was having issues with interrupt lockup with the 3.4.102 kernel.

Device Tree Entries
As my system, the AW-SOM A20 DIMM, is similar to the cubieboard2, I started with that file and copied it to a new name (cd arch/arm/boot/dts ; cp sun7i-a20-cubieboard2.dts sun7i-a20-prismlx.dts). My board uses EINT16, EINT18 and EINT20 for external interrupts. So, here are the additions made to the dts file:

The above describes my board configuration for the interrupts. Each interrupt input pin is listed in the pinctrl list and is linked to the platform driver code via the compatible entry. Thus, if your platform driver simply asks for 'platform_get_irq(pdev, 0)', the irq returned would be that which matched the driver .compatible of_device_id with that of the device tree. It appears that you could use platform_get_irq_byname to get several interrupts into a single platform driver?

Note, the entry for interrupts-extended in the rebooter description has <&pio 20 0>? The 20 is the external interrupt number (EINT20) and the 0 is irrelevant, this value has no affect on the interrupt line sensing. The PIO_INT_CFG register trigger value is set by the IRQF_ when you use request_irq in your driver (e.g. IRQF_TRIGGER_HIGH sets a value of 0x02 in the PIO_INT_CFGx register for that external pin). This doesn't seem to be correct anymore since the new 4.x kernel hp197 (talk)

A Simple Platform Driver
This is a simple driver which requests the 'rebooter' IRQ (EINT20). What you should note is the IRQF_TRIGGER_FALLING of request_irq. It is in the call to request_irq that the active level / edge of the interrupt request (input pin) is specified.

Doing an ismod of the driver should give you something like this in /proc/interrupts: Of course, if you tap on the EINT20 pin with a wire to GROUND, you should see the 'rebooter_irq' count change.

Using the right clock
On the 3.19 kernel, the PIO interrupt sampling clock is set to the default value of 32KHz. This is probably "good enough" if you were to only have some push buttons tied to those external interrupts, but, not good enought if you hang a serial UART on one of those interrupt lines. The sampling rate of 32KHz would have you missing some of the interrupts as data comes in, so, you better have a pretty deep fifo in that UART...

This patch made by Maxime Ripard will allow you to change the PIO Interrupt Debounce clock from 32KHz to 24MHz (tested on kernel 4.1rc1, Hans' branch sunxi-wip):

=External Links=
 * Simple tutorial by patwood