I'm using an i.MX6 (IMXULL) application processor, and want to know in software when the power-off button has been pressed:
Luckily, the IMX6ULL reference manual explains that this should be possible:
Section 10.5: ONOFF Button
The chip supports the use of a button input signal to request main SoC power state changes (i.e. On or Off) from the PMU. The ONOFF logic inside of SNVS_LP allows for connecting directly to a PMIC or other voltage regulator device. The logic takes a button input signal and then outputs a
pmic_en_b
andset_pwr_off_irq
signal. [...] The logic has two different modes of operation (Dumb and Smart mode). The Dumb PMIC Mode usespmic_en_b
to issue a level signal for on and off. Dumb pmic mode has many different configuration options which include (debounce, off to on time, and max time out).
(Also available in condensed form here on page 18)
Therefore, I have built a trivially simple kernel module to try and capture this interrupt:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/interrupt.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Doe <j.doe@acme.inc>");
// Forward declaration
irqreturn_t irq_handler (int, void *);
// Number of interrupt to capture
#define INTERRUPT_NO 36
static int __init pwr_ctl_init (void)
{
pr_err("init()\n");
return request_irq(INTERRUPT_NO, irq_handler, IRQF_SHARED, "onoff-button",
(void *)irq_handler);
}
static void __exit pwr_ctl_exit (void)
{
pr_err("exit()\n");
free_irq(INTERRUPT_NO, NULL);
}
irqreturn_t irq_handler (int irq, void *dev_irq)
{
pr_err("interrupt!\n");
return IRQ_HANDLED;
}
module_init(pwr_ctl_init);
module_exit(pwr_ctl_exit);
However, I cannot find any information about what the number of the interrupt is. When searching on the internet, all I get is this one NXP forum post:
Which hints it should be 36
. However, I have found that this isn't the case on my platform. When I check /proc/interrupts
36 is already occupied by 20b4000.ethernet
. Because the application manual also mentions that it is generated by the SNVS
low power system, I checked the device-tree and found the following information:
snvs_poweroff: snvs-poweroff {
compatible = "syscon-poweroff";
regmap = <&snvs>;
offset = <0x38>;
value = <0x60>;
mask = <0x60>;
status = "disabled";
};
snvs_pwrkey: snvs-powerkey {
compatible = "fsl,sec-v4.0-pwrkey";
regmap = <&snvs>;
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
linux,keycode = <KEY_POWER>;
wakeup-source;
status = "disabled";
};
This information seems useful for knowing that SNVS is the interrupt controller, but not how to capture this set_pwr_off_irq
signal.
This edit answers some user questions, and then goes into new information about the problem I have since discovered:
NXP i.MX 6UltraLite / 6ULL / 6ULZ
ARM Cortex A7.snvs_pwrkey
driver (see here) is enabled. My modification consists of adding a single kprint
statement to the interrupt routine to see if the button trips it. This did not workThe answer is rather anticlimactic. In short, there was a device-tree overlay that was disabling my changes to snvs_pwrkey
, even when I had enabled it. Once I located and removed the overlay, the driver (snvs_pwrkey.c
) was working as expected.
As for the IRQ number, it turns out that the IRQ for the power button is 45
as interpreted through Linux. The interrupt is not configured for sharing, so my kernel module could not be loaded.
If you want to capture power button toggle events, I suggest modifying the driver to add some output, and then perhaps adding a udev
rule to capture button presses. I will update my answer with an example ASAP.