Abstract:
Based on the previous blog post, this article adds an analysis on how to increase the wake-up source after the standby mode.
Android standby process and IRQ switching process
For Android Developers, there may be questions about why our mobile phones or tablets, Volume keys, and screens won't be on, while power keys and screens will be on? Or how can we make the volume button light up the screen (of course, from the developer's perspective, it has nothing to do with practicality)
The overall management of IRQ In the android standby process is:
1. All IRQ are disable
2. Some IRQ are enable
3. Waiting for IRQ to wake up
The reason why IRQ can be managed in such a unified manner does not need to know what application registered IRQ is through the IRQ attribute, this attribute needs to be clearly considered when each module is interrupted when requesting to register its own module.
Let's try to see if you can enable some IRQ, such as the volume button, as you think.
1. All IRQ are disable
arch_suspend_disable_irqs();
2. Some IRQ are enable
List_for_each_entry_reverse (CLS, & system_kset-> list, kset. kobj. entry) {pr_debug ("suspending type '% s': \ n", kobject_name (& CLS-> kset. kobj); list_for_each_entry (sysdev, & CLS-> kset. list, kobj. entry) {pr_debug ("% s \ n", kobject_name (& sysdev-> kobj);/* Call auxillary drivers first */list_for_each_entry (DRV, & CLS-> drivers, entry) {If (DRV-> suspend) {// In the suspend callback of the driver, open the IRQ to be enabled and enable the Wakeup function of the IRQ. ret = DRV-> S Uspend (sysdev, State); If (RET) goto aux_driver;} warn_once (! Irqs_disabled (), "interrupts enabled after % pf \ n", DRV-> suspend);}/* now call the generic one */If (CLS-> suspend) {ret = CLS-> suspend (sysdev, State); If (RET) goto cls_driver; warn_once (! Irqs_disabled (), "interrupts enabled after % pf \ n", CLS-> suspend );}}}
To manage IRQ, we only need to know the number of IRQ IDs. In the CPU design, there will be a GIC module, and each IRQ can have a unique ID.
In Linux, The enable_irq_wake and disable_irq_wake functions enable_irq_wake functions enable the wake function of IRQ by passing in the irq id.
For example
int irq_wake_id[IRQ_WAKE_MAX];void pm_irqwake_enable(void){enable_irq_wake(irq_wake_id[IRQ_WAKE_TS]);enable_irq_wake(irq_wake_id[IRQ_WAKE_GS]);enable_irq_wake(irq_wake_id[IRQ_WAKE_KEY_MENU]);return;}void pm_irqwake_disable(void){disable_irq_wake(irq_wake_id[IRQ_WAKE_GS]);disable_irq_wake(irq_wake_id[IRQ_WAKE_TS]);disable_irq_wake(irq_wake_id[IRQ_WAKE_KEY_MENU]);return;}
These irq ids can be obtained through cat proc/interrupts. Of course, a better way is to use a function to obtain them. I am lazy and then define the IDS.