1.gpio相关的中断控制器(msm_tlmm_irq) 初始化
IRQCHIP_DECLARE定义irq chip
#define IRQCHIP_DECLARE(name,compstr,fn) \
static const struct of_device_id irqchip_of_match_##name \
__used __section(__irqchip_of_table) \
= { .compatible = compstr, .data = fn }
IRQCHIP_DECLARE(tlmmv3_irq, "qcom,msm-tlmm-gp", irq_msm_gpio_init);
//定义IRQCHIP_DECLARE之后,相应的内容会保存到__irqchip_of_table里边。
//__irqchip_of_table在vmlinux.lds文件里边被放到了__irqchip_begin和__irqchip_of_end之间
#ifdef CONFIG_IRQCHIP
#define IRQCHIP_OF_MATCH_TABLE() \
. = ALIGN(8); \
VMLINUX_SYMBOL(__irqchip_begin) = .; \
*(__irqchip_of_table) \
*(__irqchip_of_end)
#endif
__irqchip_begin和__irqchip_of_end的内容被drivers/irqchip/irqchip.c文件读出并根据其在device tree里边的内容进行初始化。
对应的irq chip在device tree中的设置如下:
/*General purpose pins*/
gp: gp {
qcom,num-pins = <122>;
#qcom,pin-cells = <1>;
msm_gpio: msm_gpio {
compatible = "qcom,msm-tlmm-gp";
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
num_irqs = <122>;
};
};
其irq chip对应的函数实现也可以看到
static struct msm_tlmm_irq_chip msm_tlmm_gp_irq = {
.irq_chip_extn = &mpm_tlmm_irq_extn,
.chip = {
.name = "msm_tlmm_irq",
.irq_mask = msm_tlmm_irq_mask,
.irq_unmask = msm_tlmm_irq_unmask,
.irq_ack = msm_tlmm_irq_ack,
.irq_set_type = msm_tlmm_irq_set_type,
.irq_set_wake = msm_tlmm_irq_set_wake,
.irq_disable = msm_tlmm_irq_disable,
},
.apps_id = TLMM_APPS_ID_DEFAULT,
.domain_ops = &msm_tlmm_gp_irqd_ops,
.handler = msm_tlmm_gp_handle_irq,
};
2.中断函数调用流程
http://blog.csdn.net/hongzg1982/article/details/49070973
这里已经说了大概的流程,但到了调用irq_handler的时候
.macro irq_handler
#ifdef CONFIG_MULTI_IRQ_HANDLER
ldr r1, =handle_arch_irq
mov r0, sp
adr lr, BSYM(9997f)
ldr pc, [r1]
#else
arch_irq_handler_default
#endif
9997:
.endm
这里根据CONFIG_MULTI_IRQ_HANDLER定义与否,会调用系统自己设置的handle_arch_irq或者调用默认的arch_irq_handler_defult。像高通平台是已经定义了CONFIG_MULTI_IRQ_HANDLER,并调用kernel/arch/arm/kernel/irq.c文件中的set_handle_irq()函数设置handle_arch_irq为gic_handle_irq()函数了的[kernel/drivers/irqchip/irq-gic.c]
static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
struct gic_chip_data *gic = &gic_data[0];
void __iomem *cpu_base = gic_data_cpu_base(gic);
do {
irqstat = readl_relaxed_no_log(cpu_base + GIC_CPU_INTACK);
irqnr = irqstat & ~0x1c00;
if (likely(irqnr > 15 && irqnr < 1021)) {
irqnr = irq_find_mapping(gic->domain, irqnr);
handle_IRQ(irqnr, regs);
uncached_logk(LOGK_IRQ, (void *)(uintptr_t)irqnr);
continue;
}
if (irqnr < 16) {
writel_relaxed_no_log(irqstat, cpu_base + GIC_CPU_EOI);
#ifdef CONFIG_SMP
handle_IPI(irqnr, regs);
#endif
uncached_logk(LOGK_IRQ, (void *)(uintptr_t)irqnr);
continue;
}
break;
} while (1);
}
3.设置中断唤醒!!
以gpio-key的为例:以下是gpio-key的device tree设置
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
pinctrl-0 = <&gpio_key_active>;
pinctrl-1 = <&gpio_key_suspend>;
home_key {
label = "home_key";
gpios = <&msm_gpio 109 0x1>;
linux,input-type = <1>;
linux,code = <172>;
gpio-key,wakeup;
debounce-interval = <15>;
};
vol_up {
label = "volume_up";
gpios = <&msm_gpio 107 0x1>;
linux,input-type = <1>;
linux,code = <115>;
debounce-interval = <15>;
};
};
可以看到home_key里边有gpio-key,wakeup;
这个在gpio_keys相关的驱动力,在suspend的时候需要使用enable_irq_wake来进行设置才能通过home_key中断唤醒系统。
static int gpio_keys_suspend(void){
...
if (device_may_wakeup(global_dev)) {
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
if (bdata->button->wakeup)//buttong->wakeup就是通过读device tree的gpio-key,wakeup设置的
enable_irq_wake(bdata->irq);//设置该中断可唤醒系统!!具体设置看上面的中断控制器内容
}
} else {
mutex_lock(&input->mutex);
if (input->users)
gpio_keys_close(input);
mutex_unlock(&input->mutex);
}
...
}
当然在resume的时候也要对应地取消中断函数的唤醒。
enable_irq_wake()和disable_irq_wake()函数中可以看到,irq_desc的wake_depth会记录enable或者disable的次数。
所以需要对应地enable和disable每个irq的中断唤醒功能。
static void gpio_keys_resume(void)
{
...
if (device_may_wakeup(global_dev)) {
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
if (bdata->button->wakeup)
disable_irq_wake(bdata->irq);
}
} else {
mutex_lock(&input->mutex);
if (input->users)
error = gpio_keys_open(input);
mutex_unlock(&input->mutex);
}
...
}
上面device_may_wakeup()检查power.can_wakeup,power.wakeup
static inline bool device_may_wakeup(struct device *dev)
{
return dev->power.can_wakeup && !!dev->power.wakeup;
}
这里的power.can_wakeup在gpio_keys_probe()函数的device_init_wakeup()函数里设置。
################################################
IRQ相关的宏
CONFIG_ARM_GIC //GIC中断控制器
CONFIG_SPARSE_IRQ
CONFIG_MSM_SHOW_RESUME_IRQ
CONFIG_HAVE_IRQ_TIME_ACCOUNTING
CONFIG_USE_PINCTRL_IRQ
CONFIG_OF_IRQ
CONFIG_IRQ_WORK
CONFIG_SPARSE_IRQ
CONFIG_TRACE_IRQFLAGS_SUPPORT
CONFIG_HARDIRQS_SW_RESEND
CONFIG_SEC_DEBUG_IRQ_EXIT_LOG
CONFIG_GENERIC_IRQ_PROBE
CONFIG_MAY_HAVE_SPARSE_IRQ
CONFIG_GENERIC_IRQ_SHOW
CONFIG_IRQ_DOMAIN
CONFIG_MULTI_IRQ_HANDLER
CONFIG_IRQCHIP
CONFIG_MSM_IRQ
###############################################
#cat /proc/interrupts 打印的内容
cat interrupts
CPU0 CPU1 CPU2 CPU3
20: 1086204 465271 219385 125476 GIC arch_timer
35: 0 0 0 0 GIC apps_wdog_bark
39: 1274816 928934 431484 252063 GIC arch_mem_timer
47: 45 0 0 0 GIC cpr
56: 0 0 0 0 GIC modem
57: 6678 0 0 0 GIC qcom,smd-modem
58: 2 0 0 0 GIC qcom,smsm-modem
59: 5 0 0 0 GIC smp2p
65: 10820 0 0 0 GIC kgsl-3d0
75: 0 0 0 0 GIC msm_iommu_global_cfg_irq, msm_iommu_global_cfg_irq
76: 503 0 0 0 GIC msm_vidc
82: 9 0 0 0 GIC cci
83: 2 0 0 0 GIC csid
84: 0 0 0 0 GIC csid
89: 2 0 0 0 GIC
102: 0 0 0 0 GIC msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_secure_irq, msm_iommu_secure_irq, msm_iommu_secure_irq, msm_iommu_secure_irq, msm_iommu_secure_irq, msm_iommu_secure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq, msm_iommu_nonsecure_irq
104: 3821 0 0 0 GIC MDSS
110: 0 0 0 0 GIC csiphy
111: 0 0 0 0 GIC csiphy
127: 0 0 0 0 GIC i2c-msm-v2-irq
128: 7893 0 0 0 GIC i2c-msm-v2-irq
130: 0 0 0 0 GIC i2c-msm-v2-irq
131: 0 0 0 0 GIC i2c-msm-v2-irq
132: 0 0 0 0 GIC i2c-msm-v2-irq
140: 576 0 0 0 GIC msm_serial_hsl0
155: 132532 0 0 0 GIC mmc0
157: 0 0 0 0 GIC mmc1
166: 511 0 0 0 GIC msm_otg, msm_hsusb
170: 663 0 0 0 GIC 7824900.sdhci
172: 0 0 0 0 GIC msm_otg
174: 1127 0 0 0 GIC qcom,smd-wcnss
175: 5 0 0 0 GIC smp2p
176: 0 0 0 0 GIC qcom,smsm-wcnss
177: 1769 0 0 0 GIC wcnss_wlan
178: 630 0 0 0 GIC wcnss_wlan
181: 0 0 0 0 GIC wcnss
200: 244890 133756 49164 25615 GIC qcom,smd-rpm
203: 427701 370801 115006 64144 GIC 601d0.qcom,mpm
216: 0 0 0 0 GIC tsens_interrupt
222: 677 0 0 0 GIC 200f000.qcom,spmi
239: 0 0 0 0 GIC sps
240: 575 0 0 0 GIC 1000000.pinctrl
253: 2 0 0 0 GIC 7864900.sdhci
273: 0 0 0 0 GIC msm_iommu_nonsecure_irq
274: 0 0 0 0 GIC msm_iommu_nonsecure_irq
280: 2 0 0 0 GIC mobicore
288: 0 0 0 0 msm_tlmm_irq sm5703
290: 0 0 0 0 msm_tlmm_irq 7864900.sdhci cd
291: 7 0 0 0 qpnp-int qpnp_kpdpwr_status
292: 2 0 0 0 qpnp-int qpnp_resin_status
294: 2 0 0 0 qpnp-int qpnp_kpdpwr_resin_bark
295: 334 0 0 0 qpnp-int qpnp_rtc_alarm
297: 0 0 0 0 qpnp-int pm8916_tz
299: 1 0 0 0 qpnp-int qpnp_adc_tm_high_interrupt
300: 0 0 0 0 qpnp-int qpnp_adc_tm_low_interrupt
330: 0 0 0 0 msm_tlmm_irq k2hh_accel
331: 0 0 0 0 msm_tlmm_irq bcm2079x-i2c
338: 0 0 0 0 sm5703 otffail
348: 0 0 0 0 sm5703 topoff
349: 0 0 0 0 sm5703 done
357: 6 0 0 0 msm_tlmm_irq sm5703 muic micro USB
454: 569 0 0 0 msm_tlmm_irq zt7554_ts
455: 0 0 0 0 msm_tlmm_irq fuelgauge-irq
456: 0 0 0 0 msm_tlmm_irq sx9500_wifi_irq
457: 0 0 0 0 smp2p_gpio modem
458: 1 0 0 0 smp2p_gpio error_ready_interrupt
459: 1 0 0 0 smp2p_gpio modem
460: 0 0 0 0 smp2p_gpio modem
489: 0 0 0 0 smp2p_gpio wcnss
490: 1 0 0 0 smp2p_gpio error_ready_interrupt
491: 1 0 0 0 smp2p_gpio wcnss
492: 0 0 0 0 smp2p_gpio wcnss
521: 0 0 0 0 msm_tlmm_irq home_key
522: 0 0 0 0 msm_tlmm_irq volume_up
523: 0 0 0 0 msm_tlmm_irq sec_headset_detect
IPI0: 0 335 335 335 CPU wakeup interrupts
IPI1: 22678 22996 17470 15718 Timer broadcast interrupts
IPI2: 481360 374947 186478 142656 Rescheduling interrupts
IPI3: 84655 100015 156993 161249 Function call interrupts
IPI4: 1204 6730 6209 7108 Single function call interrupts
IPI5: 0 0 0 0 CPU stop interrupts
IPI6: 0 0 0 0 CPU backtrace
Err: 0