Linux 中断(irq)控制器以及device tree设置

GPIO相关中断(高通平台为例)

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

你可能感兴趣的:(linux,IRQ)