框图   LPC3250有3个中断控制器,分别是1个主中断控制器(MIC)和2个子中断控制器(SIC1、SIC2)。整个框图以及它们的关系如下图:

 

    寄存器汇总

   每个控制器都有自己的一组寄存器,如下表所列:
 

寄存器描述

   每个中断控制器的寄存器都包括:中断使能寄存器、中断原始状态寄存器、中断状态寄存器、中断触发极性寄存器、中断触发类型寄存器以及中断类型寄存器。
    中断时能寄存器      :禁止或者允许外设的独立中断连接到相应的控制器;
                                  0——禁止,1——使能中断。
    中断原始状态寄存器:
                            读:0,中断源没有产生中断
                                  1,中断源产生了中断
                            写:0,无任何操作
                                  1,清除边沿触发的中断标志
    中断状态寄存器     :反应处于pending状态的中断,0——没有pending,1——处于pending状态
    中断触发极性寄存器:中断触发极性选择,0——低电平或者下降沿触发,1——高电平或者上升沿触发
    中断类型触发寄存器:中断触发类型选择,0——电平触发,1——边沿触发
    中断类型寄存器      :中断类型选择,0——IRQ中断,1——FIQ中断。
 
   
    这些寄存器在移植代码中分别被表示为:
#define INTC_MASK                    0x00
#define INTC_RAW_STAT           0x04
#define INTC_STAT                    0x08
#define INTC_POLAR                  0x0C
#define INTC_ACT_TYPE             0x10
#define INTC_TYPE                     0x14
 
   另外,系统对每个中断控制器的中断源都分配了编号,其中MICR的占用0~31号,SIC1的中断源占用32~63号,SIC2的中断源占用64~95号,所以分别为SIC1和SIC2定义了32以及64的偏移量。
#define INTC_SIC1_OFFS                32
#define INTC_SIC2_OFFS                64
 
 
Table 47.Interrupt controller registry summaryAddressRegister nameDescription                 Reset valueType

    主中断控制器相关寄存器

0x4000 8000   MIC_ER       Enable Register for the Main Interrupt Controller                             0                      R/W
0x4000 8004   MIC_RSR      Raw Status Register for the Main Interrupt Controller                         x                      R/W
0x4000 8008   MIC_SR       Status Register for the Main Interrupt Controller                             0                       RO
0x4000 800C   MIC_APR      Activation Polarity select Register for the Main Interrupt Controller         0                      R/W
0x4000 8010   MIC_ATR      Activation Type select Register for the Main Interrupt Controller             0                      R/W
0x4000 8014   MIC_ITR      Interrupt Type select Register for the Main Interrupt Controller              0                      R/W
 

    子中断控制器1相关寄存器

0x4000 C000   SIC1_ER          Enable register for Sub Interrupt Controller 1                                                0                      R/W     
0x4000 C004   SIC1_RSR        Raw Status Register for Sub Interrupt Controller 1                                          -                      R/W 
0x4000 C008   SIC1_SR         Status Register for Sub Interrupt Controller 1                                                 0                      RO
0x4000 C00C   SIC1_APR       Activation Polarity select Register for Sub Interrupt Controller 1                0                     R/W
0x4000 C010   SIC1_ATR       Activation Type select Register for Sub Interrupt Controller 1                       0                 R/W
0x4000 C014   SIC1_ITR       Interrupt Type select Register for Sub Interrupt Controller 1                        0                     R/W
 

    子中断控制器2相关寄存器

0x4001 0000   SIC2_ER      Enable register for Sub Interrupt Controller 2                                                0                      R/W
0x4001 0004   SIC2_RSR     Raw Status Register for Sub Interrupt Controller 2                                          x                      R/W
0x4001 0008   SIC2_SR    Status Register for Sub Interrupt Controller 2                                                  0                      RO
0x4001 000C   SIC2_APR     Activation Polarity select Register for Sub Interrupt Controller 2         0                      R/W
0x4001 0010   SIC2_ATR     Activation Type select Register for Sub Interrupt Controller 2             0                      R/W
0x4001 0014   SIC2_ITR     Interrupt Type select Register for Sub Interrupt Controller 2              0                      R/W
 

头文件irqs.h

    irqs.h文件,对IRQ相关的寄存器进行了定义,对系统已经使用的中断号也进行了定义。如与GPIO_00明确相关的定义:
#define IRQ_GPIO_00(INTC_SIC2_OFFS + 0)
    表示IRQ_GPIO_00在系统中的中断号为64。

LPC3250 irq底层API

    详见./arch/arm/mach-lpc32xx/irq-lpc32xx.c文件,其中提供了如下API:
static void lpc32xx_mask_irq(unsigned int irq)
static void lpc32xx_unmask_irq(unsigned int irq)
static void lpc32xx_mask_ack_irq(unsigned int irq)
static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
 
    但是,这些API并不开放给用户使用,而是通过注册irq,为用户提供更高层的API:
static struct irq_chip lpc32xx_irq_chip = {
.ack = lpc32xx_mask_ack_irq,
.mask = lpc32xx_mask_irq,
.unmask = lpc32xx_unmask_irq,
.set_type = lpc32xx_set_irq_type, //设置中断触发类型
};
    最终用户使用的设置中断触发类型的API是set_irq_type()函数。
 
 
 
    LPC3250各中断源的中断号详见irqs.h文件。
   LPC3250的中断类型完整包括:低电平触发、高电平触发,下降沿触发和上升沿触发。Linux系统中,中断触发类型定义在:./include/linux/irq.h文件中:
32 /*
33  * IRQ line status.
34  *
35  * Bits 0-7 are reserved for the IRQF_* bits in linux/interrupt.h
36  *
37  * IRQ types   
38  */
39 #define IRQ_TYPE_NONE                         0x00000000  /* Default, unspecified type */
40 #define IRQ_TYPE_EDGE_RISING             0x00000001  /* Edge rising type */
41 #define IRQ_TYPE_EDGE_FALLING           0x00000002  /* Edge falling type */
42 #define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
43 #define IRQ_TYPE_LEVEL_HIGH               0x00000004  /* Level high type */
44 #define IRQ_TYPE_LEVEL_LOW               0x00000008  /* Level low type */
45 #define IRQ_TYPE_SENSE_MASK              0x0000000f  /* Mask of the above */
46 #define IRQ_TYPE_PROBE                        0x00000010  /* Probing in progress */
 
 
 
    系统已经为各路中断设置了默认值:
/* Set default mappings */
lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0);
lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, INTC_SIC1_OFFS);
lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, INTC_SIC2_OFFS);
 
    各中断寄存器的默认值如下:
36 /*
37  * Default value represeting the Activation polarity of all internal
38  * interrupt sources
39  */
40 #define MIC_APR_DEFAULT        0x3FF0EFF8
41 #define SIC1_APR_DEFAULT        0xFBD27186
42 #define SIC2_APR_DEFAULT        0x801810C0
43
44 /*
45  * Default value represeting the Activation Type of all internal
46  * interrupt sources. All are level senesitive.
47  */
48 #define MIC_ATR_DEFAULT         0x00000000
49 #define SIC1_ATR_DEFAULT        0x00026000
50 #define SIC2_ATR_DEFAULT        0x00000000
51
   在使用中断之前首先检查是否为所需要的中断类型,如果不是,可以直接修改默认值,或者调用系统提供的API进行重新设定。
 
 

中断初始化入口

    board-smartarm3250.c的机型描述:
 
MACHINE_START (LPC3XXX, "SmartARM3250 board with the LPC3250 Microcontroller")
    /* Maintainer: Kevin Wells, NXP Semiconductors */
    .phys_io= UART5_BASE,
    .io_pg_offst= ((io_p2v (UART5_BASE))>>18) & 0xfffc,
    .boot_params= 0x80000100,
    .map_io= lpc32xx_map_io,
    .init_irq= lpc32xx_init_irq,               //中断初始化入口
    .timer= &lpc32xx_timer,
    .init_machine= smartarm3250_board_init,
MACHINE_END
 

lpc32xx_init_irq

    lpc32xx_init_irq在irq-lpc32xx.c中实现。
void __init lpc32xx_init_irq(void)
{
unsigned int i, vloc;
 
/* Setup MIC */
vloc = io_p2v(MIC_BASE);
__raw_writel(0, (vloc + INTC_MASK));
__raw_writel(MIC_APR_DEFAULT, (vloc + INTC_POLAR));
__raw_writel(MIC_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
 
/* Setup SIC1 */
vloc = io_p2v(SIC1_BASE);
__raw_writel(0, (vloc + INTC_MASK));
__raw_writel(SIC1_APR_DEFAULT, (vloc + INTC_POLAR));
__raw_writel(SIC1_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
 
/* Setup SIC2 */
vloc = io_p2v(SIC2_BASE);
__raw_writel(0, (vloc + INTC_MASK));
__raw_writel(SIC2_APR_DEFAULT, (vloc + INTC_POLAR));
__raw_writel(SIC2_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
 
/* Configure supported IRQ's */
for (i = 0; i < NR_IRQS; i++) {
set_irq_flags(i, IRQF_VALID);
set_irq_chip(i, &lpc32xx_irq_chip);                      //set_irq_chip
}
 
/* Set default mappings */
lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0);
lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, INTC_SIC1_OFFS);
lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, INTC_SIC2_OFFS);
 
/* mask all interrupts except SUBIRQA and SUBFIQ */
__raw_writel((1 << IRQ_SUB1IRQ) | (1 << IRQ_SUB2IRQ) |
(1 << IRQ_SUB1FIQ) | (1 << IRQ_SUB2FIQ),
(io_p2v(MIC_BASE) + INTC_MASK));
__raw_writel(0, (io_p2v(SIC1_BASE) + INTC_MASK));
__raw_writel(0, (io_p2v(SIC2_BASE) + INTC_MASK));
}
 

lpc32xx_irq_chip

   在lpc32xx_init_irq中调用set_irq_chip,其中一个参数是lpc32xx_irq_chip,在其中实现了mask、unmask、set_type等方法。
static struct irq_chip lpc32xx_irq_chip = {
.ack = lpc32xx_mask_ack_irq,
.mask = lpc32xx_mask_irq,
.unmask = lpc32xx_unmask_irq,
.set_type = lpc32xx_set_irq_type,
};
 
 

LPC3250中断处理程序

    中断处理完毕,需要清除对应中断的中断标志,然后才能返回。
    键盘中断范例:
/* Clear IRQ */
__raw_writel(1, KS_IRQ(kscandat->kscan_base))
 
   对于没有特别中断控制器的中断源,因为没有中断寄存器,则需要直接清除对应MIC或者SIC的对应位,如GPIO作为中断输入,则中断服务程序需要清除SIC的对应位。
 
 
 

现有的范例

    ./arch/arm/mach-lpc32xx/arch-lpc32xx.c
    ./drivers/input/keyboard/lpc32xx_keys.c
 
    arch-lpc32xx.c中的代码段:
303 #if defined(CONFIG_KEYBOARD_LPC32XX)
304 static struct resource kscan_resources[] = {
305     [0] = {
306         .start  = KSCAN_BASE,
307         .end    = KSCAN_BASE + SZ_4K - 1,
308         .flags  = IORESOURCE_MEM,
309     },
310     [1] = {
311         .start  = IRQ_KEY,
312         .end    = IRQ_KEY,
313         .flags  = IORESOURCE_IRQ,
314     },
315
316 };
317 static struct platform_device kscan_device = {
318     .name       = "lpc32xx_keys",
319     .id     = 0,
320     .dev        = {
321         .platform_data  = &lpc32xx_kscancfg,
322     },
323     .num_resources  = ARRAY_SIZE(kscan_resources),
324     .resource   = kscan_resources,
325 };
326 #endif
 
    lpc32xx_kscancfg:
90 struct lpc32XX_kscan_cfg lpc32xx_kscancfg = {                                                                                                                                
91     .matrix_sz  = KMATRIX_SIZE,
92     .keymap     = lpc32xx_keymaps,
93     /* About a 30Hz scan rate based on a 32KHz clock */
94     .deb_clks   = 3,
95     .scan_delay = 34,
96 };
posted on 2012-04-28 14:48  风行雪舞  阅读(609)  评论(0编辑  收藏  举报
无觅相关文章插件,快速提升流量