When there is a change of voltage level on P0-P7 pins, PCA9555PW will generate interrupt on INT pin. The driver (running on SoC) can read the status of P0-P7 pins via I2C (SCL/SDA pins) and generate separate interrupts for each of P0-P7 pins. This is why this driver acts as interrupt controller.
Consider next configuration:
One push button changes level on P4 pin, tempting PCA9555PW to generate interrupt. Interrupt from PCA9555PW is connected to GPIO5 IP-core (inside of SoC), and it uses line #9 of that GPIO5 module to notify CPU about interrupt. So we can say that PCA9555PW is cascaded to GPIO5 controller. GPIO5 also acts as interrupt controller, and it's cascaded to GIC interrupt controller.
The meaning of properties is as follows:
interrupt-controller
property defines that device generates interrupts; it will be needed further to use this node as interrupt-parent
in each push button node.
#interrupt-cells
defines format of interrupts
property; in our case it's 2
: 1 cell for line number and 1 cell for interrupt type
interrupt-parent
and interrupts
properties are describing interrupt line connection
CPU now is in interrupt context in GIC interrupt handler. From gic_handle_irq()
it calls handle_domain_irq()
, which in turn calls generic_handle_irq()
. See Documentation/gpio/driver.txt for details. Now we are in SoC's GPIO controller IRQ handler.
SoC's GPIO driver also calls generic_handle_irq()
to run handler, which is set for each particular pin. See for example how it's done in omap_gpio_irq_handler()
. Now we are in PCA9555PW IRQ handler.
PCA9555PW IRQ handler calls handle_nested_irq()
.
Finally, gpio_keys_gpio_isr()
is called.
The following steps allow you to enable rgb led's and push buttons on 8MIC-RPI-MX8 board with i.MX 8M Mini Applications Processor Evaluation Kit (EVKB). You have to use a led driver and change the device tree.
Clone the i.MX Linux Kernel repo to the home directory.
cd ~
git clone https://source.codeaurora.org/external/imx/linux-imx
This guide will use the following commit which corresponds to Kernel 5.10.35-2.0.
cd linux-imx/
git checkout -b RGB ef3f2cfc6010
Download the "0001-Enable-RGB-LED-s-and-push-buttons-on-8MIC-RPI-MX8-bo.patch" file attached to this post and copy it into linux-imx directory, then apply the patch.
cp 0001-Enable-RGB-LED-s-and-push-buttons-on-8MIC-RPI-MX8-bo.patch ~/linux-imx/
cd ~/linux-imx/
patch < 0001-Enable-RGB-LED-s-and-push-buttons-on-8MIC-RPI-MX8-bo.patch
When prompted, select the file to patch:
File to patch: arch/arm64/boot/dts/freescale/imx8mm-evk-8mic-revE.dts patching file arch/arm64/boot/dts/freescale/imx8mm-evk-8mic-revE.dts
Then setup your toolchain, for example:
source /opt/fsl-imx-wayland/5.10-hardknott/environment-setup-cortexa53-crypto-poky-linux
Generate config file.
make imx_v8_defconfig
Compile the device tree.
make freescale/imx8mm-evk-8mic-revE.dtb
Copy the .dtb file to the EVK, for example with scp:
scp imx8mm-evk-8mic-revE.dtb root@<EVK_IP>:/home/root
Alternatively, you may copy the .dtb file directly to the FAT32 partition where the Kernel and Device Tree files are located.
Obtain the leds-pca995x.h file in the next site:
Copy it into the next path:
cp leds-pca995x.h ~/linux-imx/include/linux
Create a new directory.
mkdir ~/linux-imx/PCA9955
Create a makefile.
cd ~/linux-imx/PCA9955
vim Makefile
KERNEL_ROOT?=~/linux-imx
obj-m += leds-pca995x.o
all: make -C $(KERNEL_ROOT) M=$(PWD) modules
clean: make -C $(KERNEL_ROOT) M=$(PWD) clean
Press the key "Esc" and then:
:wq
Obtain the leds-pca995x.c file in the next site:
Copy it into the next path:
cp leds-pca995x.c ~/linux-imx/PCA9955
Obtain 0001-PCA9955BTW.patch file and copy it into the next path:
cp 0001-PCA9955BTW.patch ~/linux-imx/PCA9955
Apply the patch.
patch < 0001-PCA9955BTW.patch
Then setup your toolchain, for example:
source /opt/fsl-imx-wayland/5.10-hardknott/environment-setup-cortexa53-crypto-poky-linux
Generate .ko file.
cd ~/linux-imx/PCA9955
make all
Copy the .ko file to the EVK, for example with scp:
scp leds-pca995x.ko root@192.168.100.105:/home/root
NOTE: The linux version of .ko file must be the same as EVK.
To copy the updated device tree to the corresponding partition, first create a directory.
mkdir Partition_1
Mount the partition one.
mount /dev/mmcblk1p1 Partition_1/
Copy or move the device tree into partition one.
cp imx8mm-evk-8mic-revE.dtb Partition_1/
Reboot the board.
reboot
Stop on u-boot and modify the .dtb file to use the device tree for 8mic board.
u-boot=> editenv fdtfile
edit: imx8mm-evk-8mic-revE.dtb
u-boot=> saveenv
Saving Environment to MMC... Writing to MMC(1)... OK
u-boot=> boot
Execute the following command to load the led driver into the kernel.
insmod leds-pca995x.ko
And you will see something like:
[ 249.359103] leds_pca995x: loading out-of-tree module taints kernel.
[ 249.366864] ALL
[ 249.368740] ALL 0
[ 249.370667] ALL 1
[ 249.372609] ALL 2
[ 249.374536] ALL 2
[ 249.376475] ALL 2
[ 249.378401] ALL 2
[ 249.380338] ALL 2
[ 249.382264] ALL 2
[ 249.384202] ALL 2
[ 249.386127] ALL 2
[ 249.388063] ALL 2
[ 249.389989] ALL 2
[ 249.391913] ALL 2
[ 249.393847] ALL 2
[ 249.395774] ALL 2
[ 249.397709] ALL 2
[ 249.399635] ALL 2
[ 249.401568] ALL 2
[ 249.403496] ALL 3
If you changed the device tree, you can turn on a led with the following command:
echo 250 > /sys/class/leds/pca995x\:blue0/brightness
To turn off a led:
echo 0 > /sys/class/leds/pca995x\:blue0/brightness
The red, blue and green leds can be turned on at different intensities provided.
If you changed the device tree, you can test the push buttons with the following command:
evtest
Select the correct number:
No device specified, trying to scan all of /dev/input/event*
Available devices:
/dev/input/event0: 30370000.snvs:snvs-powerkey
/dev/input/event1: sw_keys
/dev/input/event2: gpio_ir_recv
Select the device event number [0-2]: 1
And you will see:
Input driver version is 1.0.1
Input device ID: bus 0x19 vendor 0x1 product 0x1 version 0x100
Input device name: "sw_keys"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 67 (KEY_F9)
Event code 113 (KEY_MUTE)
Event code 114 (KEY_VOLUMEDOWN)
Event code 115 (KEY_VOLUMEUP)
Properties:
Testing ... (interrupt to exit)
Event: time 1642457988.1642457988, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 1
Event: time 1642457988.1642457988, -------------- SYN_REPORT ------------ Event: time 1642457988.1642457988, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 0
Event: time 1642457988.1642457988, -------------- SYN_REPORT ------------