框图 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 };