External interrupts

Notes on using external interrupts on the A20
Disclaimer: This is not meant to be comprehensive guide about the external interrupts (EINT0..EINT31), just my recent experience in getting them to work with the 3.19 stock kernel.

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).

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 is, admittedly, a hack. After some investigation into where (what data structure, pointer, #define) references the SOC registers in memory, I found that they are placed at 0xf009c800. This bit of code will allow you to change the PIO Interrupt Debounce clock from 32KHz to 24MHz:

It sure isn't portable, but it'll get you there...