Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1249617
  • 博文数量: 479
  • 博客积分: 12240
  • 博客等级: 上将
  • 技术积分: 4999
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-24 17:12
文章分类

全部博文(479)

文章存档

2014年(1)

2013年(1)

2012年(1)

2011年(95)

2010年(177)

2009年(167)

2008年(16)

2007年(21)

分类: LINUX

2009-10-14 20:13:53

LPC3250中断控制器

    框图

    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 summaryAddress Register name Description                 Reset value Type  

    主中断控制器相关寄存器

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

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

LPC3250 irq底层API

    详见./arch/arm/mach-lpc32xx/文件,其中提供了如下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各中断源的中断号详见文件。
    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 };

阅读(1894) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~