代码如下:
#include "key.h" // ref arch/arm/mach-s3c24xx/mach-mini2440.c how to set gpio MODULE_LICENSE("GPL"); /* datasheet: page274 — Port A(GPA): 25-output port — Port B(GPB): 11-input/out port — Port C(GPC): 16-input/output por — Port D(GPD): 16-input/output por — Port E(GPE): 16-input/output por — Port F(GPF): 8-input/output port — Port G(GPG): 16-input/output po — Port H(GPH): 9-input/output port — Port J(GPJ): 13-input/output port */ /* 中断引脚: GPF7 Input/output EINT7 – – GPF6 Input/output EINT6 – – GPF5 Input/output EINT5 – – GPF4 Input/output EINT4 – – GPF3 Input/output EINT3 – – GPF2 Input/output EINT2 GPF1 Input/output EINT1 GPF0 Input/output EINT0 */ /* GPB5, GPB6, GPB7, GPB8 --- LED1, LED2, LED3, LED4 K1: GPF1 -EINT1 K2: GPF4 -EINT4 K3: GPF2 -EINT2 K4: GPF0 -EINT0 */ /* datasheet中关于中断的介绍澹? The 24 external interrupts are requested by various signaling methods. The EXTINT register configures the signaling method among the low level trigger, high level trigger, falling edge trigger, rising edge trigger, and both edge trigger for the external interrupt request Because each external interrupt pin has a digital filter, the interrupt controller can recognize the request signal that is longer than 3 clocks. */ /* GPF相关寄存器: GPFCON 0x56000050 R/W Configures the pins of port F 0x0 GPFDAT 0x56000054 R/W The data register for port F Undef. GPFUP 0x56000058 R/W Pull-up disable register for port F 0x000 K1: GPF1 -EINT1: GPF1 [3:2] 00 = Input 01 = Output 10 = EINT[1] 11 = Reserved K2: GPF4 -EINT4: GPF4 [9:8] 00 = Input 01 = Output 10 = EINT[4] 11 = Reserved K3: GPF2 -EINT2: GPF2 [5:4] 00 = Input 01 = Output 10 = EINT2] 11 = Reserved K4: GPF0 -EINT0: GPF0 [1:0] 00 = Input 01 = Output 10 = EINT[0] 11 = Reserved */ #define S3C_ADDR_BASE 0xF6000000 #define S3C_ADDR(x) (S3C_ADDR_BASE + (x)) #define S3C2410_PA_UART (0x50000000) #define S3C2410_PA_GPIO (0x56000000) #define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */ #define S3C24XX_PA_UART S3C2410_PA_UART #define S3C24XX_VA_UART S3C_VA_UART #define S3C24XX_PA_GPIO S3C2410_PA_GPIO #define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART) #define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO) #define S3C2410_GPBCON S3C2410_GPIOREG(0x10) #define S3C2410_GPBDAT S3C2410_GPIOREG(0x14) #define S3C2410_GPBUP S3C2410_GPIOREG(0x18) #define S3C2410_GPFCON S3C2410_GPIOREG(0x50) #define S3C2410_GPFDAT S3C2410_GPIOREG(0x54) #define S3C2410_GPFUP S3C2410_GPIOREG(0x58) #define S3C2410_EXTINT0 S3C2410_GPIOREG(0x88) #define S3C2410_EXTINT1 S3C2410_GPIOREG(0x8C) #define S3C2410_EXTINT2 S3C2410_GPIOREG(0x90) static int kobox_key_open(struct inode *inode, struct file *file) { return 0; } static int kobox_key_release(struct inode *inode, struct file *file) { return 0; } static long kobox_key_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return 0; } #if 0 unsigned uiVal = 0; uiVal = readl(S3C2410_GPBCON); uiVal |= (0x01<<(2*pin)); uiVal &= ~(0x01 <<((2*pin)+1)) ; writel(uiVal, S3C2410_GPBCON); #endif /* GPF相关寄存器: GPFCON 0x56000050 R/W Configures the pins of port F 0x0 GPFDAT 0x56000054 R/W The data register for port F Undef. GPFUP 0x56000058 R/W Pull-up disable register for port F 0x000 K1: GPF1 -EINT1: GPF1 [3:2] 00 = Input 01 = Output 10 = EINT[1] 11 = Reserved K2: GPF4 -EINT4: GPF4 [9:8] 00 = Input 01 = Output 10 = EINT[4] 11 = Reserved K3: GPF2 -EINT2: GPF2 [5:4] 00 = Input 01 = Output 10 = EINT2] 11 = Reserved K4: GPF0 -EINT0: GPF0 [1:0] 00 = Input 01 = Output 10 = EINT[0] 11 = Reserved */ static void set_gpio_as_eint(void) { unsigned uiVal = 0; /* set gpf1 as eint1 */ uiVal = readl(S3C2410_GPFCON); uiVal &= ~(0x01 << 2); uiVal |= (0x01 << 3); writel(uiVal, S3C2410_GPFCON); /* set gpf4 as eint4 */ uiVal = readl(S3C2410_GPFCON); uiVal &= ~(0x01 << 8); uiVal |= (0x01 << 9); writel(uiVal, S3C2410_GPFCON); /* set gpf2 as eint2 */ uiVal = readl(S3C2410_GPFCON); uiVal &= ~(0x01 << 4); uiVal |= (0x01 << 5); writel(uiVal, S3C2410_GPFCON); /* set gpf0 as eint0 */ uiVal = readl(S3C2410_GPFCON); uiVal &= ~(0x01 << 0); uiVal |= (0x01 << 1); writel(uiVal, S3C2410_GPFCON); return; } /* GPF相关寄存器: GPFCON 0x56000050 R/W Configures the pins of port F 0x0 GPFDAT 0x56000054 R/W The data register for port F Undef. GPFUP 0x56000058 R/W Pull-up disable register for port F 0x000 K1: GPF1 -EINT1: GPF1 [3:2] 00 = Input 01 = Output 10 = EINT[1] 11 = Reserved K2: GPF4 -EINT4: GPF4 [9:8] 00 = Input 01 = Output 10 = EINT[4] 11 = Reserved K3: GPF2 -EINT2: GPF2 [5:4] 00 = Input 01 = Output 10 = EINT2] 11 = Reserved K4: GPF0 -EINT0: GPF0 [1:0] 00 = Input 01 = Output 10 = EINT[0] 11 = Reserved */ /* K1:EINT1 External interrupt 1 ARB0 K2:EINT4_7 External interrupt 4 – 7 ARB1 K3:EINT2 External interrupt 2 ARB0 K4:EINT0 External interrupt 0 ARB0 */ #define S3C2410_CPUIRQ_OFFSET (16) #define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET) /* main cpu interrupts */ #define IRQ_EINT0 S3C2410_IRQ(0) /* 16 */ #define IRQ_EINT1 S3C2410_IRQ(1) /* 17 */ #define IRQ_EINT2 S3C2410_IRQ(2) /* 18 */ #define IRQ_EINT4t7 S3C2410_IRQ(4) /* 20 */ #define IRQ_EINT4 S3C2410_IRQ(36) /* 52 */ /* * IRQF_DISABLED - keep irqs disabled when calling the action handler. * DEPRECATED. This flag is a NOOP and scheduled to be removed request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev) */ /* EXTERNAL INTERRUPT CONTROL REGISTER The 24 external interrupts are requested by various signaling methods. The EXTINT register configures the signaling method among the low level trigger, high level trigger, falling edge trigger, rising edge trigger, and both edge trigger for the external interrupt request Because each external interrupt pin has a digital filter, the interrupt controller can recognize the request signal that is longer than 3 clocks. EINT[15:0] are used for wakeup sources. 中断触发方式 EXTINTn(External Interrupt Control Register n) The 8 external interrupts can be requested by various signaling methods. The EXTINT register configures the signaling method between the level trigger and edge trigger for the external interrupt request, and also configures the signal polarity. EXTINT0 0x56000088 R/W External interrupt control register 0 0x000000 EXTINT1 0x5600008c R/W External interrupt control register 1 0x000000 EXTINT2 0x56000090 R/W External interrupt control register 2 0x000000 EXTINT0: K1:EINT1 [6:4] 000 = Low level 001 = High level 01x = Falling edge triggered, 10x = Rising edge triggered 11x = Both edge triggered K2:EINT4[18:16]000 = Low level 001 = High level 01x = Falling edge triggered,10x = Rising edge triggered 11x = Both edge triggered K3:EINT2 [10:8]000 = Low level 001 = High level 01x = Falling edge triggered,10x = Rising edge triggered 11x = Both edge triggered K4:EINT0 [2:0] 000 = Low level 001 = High level 01x = Falling edge triggered, 10x = Rising edge triggered 11x = Both edge triggered */ static irqreturn_t kobox_gpio_irq_handle(int irq, void *dev_id) { //disable_irq(IRQ_EINT0); printk("irq = %d\n", irq); //enable_irq(IRQ_EINT0); return IRQ_RETVAL(IRQ_HANDLED); } /* * These flags used only by the kernel as part of the * irq handling routines. * * IRQF_DISABLED - keep irqs disabled when calling the action handler. * DEPRECATED. This flag is a NOOP and scheduled to be removed * IRQF_SHARED - allow sharing the irq among several devices * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur * IRQF_TIMER - Flag to mark this interrupt as timer interrupt * IRQF_PERCPU - Interrupt is per cpu * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is * registered first in an shared interrupt is considered for * performance reasons) * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. * Used by threaded interrupts which need to keep the * irq line disabled until the threaded handler has been run. * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set * IRQF_NO_THREAD - Interrupt cannot be threaded * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device * resume time. */ #define IRQF_DISABLED 0x00000020 #define IRQF_SHARED 0x00000080 #define IRQF_PROBE_SHARED 0x00000100 #define __IRQF_TIMER 0x00000200 #define IRQF_PERCPU 0x00000400 #define IRQF_NOBALANCING 0x00000800 #define IRQF_IRQPOLL 0x00001000 #define IRQF_ONESHOT 0x00002000 #define IRQF_NO_SUSPEND 0x00004000 #define IRQF_FORCE_RESUME 0x00008000 #define IRQF_NO_THREAD 0x00010000 #define IRQF_EARLY_RESUME 0x00020000 static int request_irq_for_gpio(void) { int i; int ret; unsigned uiVal = 0; int nouse; /* set gpf1 as eint1, edge faling trigger */ /* key1 */ i = 1; uiVal = readl(S3C2410_EXTINT0); uiVal &= ~(0x1<<6); uiVal |= (0x1<<5); writel(uiVal, S3C2410_EXTINT0); ret = request_irq(IRQ_EINT1, kobox_gpio_irq_handle, NULL, "key1", (void *)i); if(ret) { printk("[func:%s][line:%d] request_irq failed, ret:%d!\n", __FUNCTION__,__LINE__,ret); } else { printk("[func:%s][line:%d] request_irq ok, irq:%d!\n", __FUNCTION__,__LINE__, IRQ_EINT1); } /*key2*/ i = 2; uiVal = readl(S3C2410_EXTINT0); uiVal &= ~(0x1<<18); // uiVal |= (0x1<<18); uiVal |= (0x1<<17); writel(uiVal, S3C2410_EXTINT0); // ret = request_irq(IRQ_EINT4t7, kobox_gpio_irq_handle, IRQF_SHARED, "key2", (void *)&nouse); ret = request_irq(IRQ_EINT4, kobox_gpio_irq_handle, IRQF_SHARED, "key2", (void *)&nouse); if(ret) { printk("[func:%s][line:%d] request_irq failed, ret:%d!\n", __FUNCTION__,__LINE__,ret); } else { printk("[func:%s][line:%d] request_irq ok, irq:%d!\n", __FUNCTION__,__LINE__, IRQ_EINT4); } /*key3*/ i = 3; uiVal = readl(S3C2410_EXTINT0); uiVal &= ~(0x1<<10); uiVal |= (0x1<<9); writel(uiVal, S3C2410_EXTINT0); ret = request_irq(IRQ_EINT2, kobox_gpio_irq_handle, NULL, "key3", (void *)i); if(ret) { printk("[func:%s][line:%d] request_irq failed, ret:%d!\n", __FUNCTION__,__LINE__,ret); } else { printk("[func:%s][line:%d] request_irq ok, irq:%d!\n", __FUNCTION__,__LINE__, IRQ_EINT2); } /*key4*/ i = 4; uiVal = readl(S3C2410_EXTINT0); uiVal &= ~(0x1<<2); uiVal |= (0x1<<1); writel(uiVal, S3C2410_EXTINT0); ret = request_irq(IRQ_EINT0, kobox_gpio_irq_handle, NULL, "key4", (void *)i); if(ret) { printk("[func:%s][line:%d] request_irq failed, ret:%d!\n", __FUNCTION__,__LINE__,ret); } else { printk("[func:%s][line:%d] request_irq ok, irq:%d!\n", __FUNCTION__,__LINE__, IRQ_EINT0); } return 0; } struct file_operations kobox_key_operations = { .owner = THIS_MODULE, .open = kobox_key_open, .release = kobox_key_release, .unlocked_ioctl = kobox_key_ioctl, }; //GPB0 int major; int minor; struct cdev cdev; struct class *kobox_key_class; struct device *pstdev = NULL; #define GPIO_KEY_NAME "kobox_key" int __init key_drv_init(void) { int error; dev_t dev; printk("#####enter key_drv_init!\n"); major = register_chrdev(0, GPIO_KEY_NAME, &kobox_key_operations); if (major < 0) { printk(" can't register major number\n"); return major; } /* create class */ kobox_key_class = class_create(THIS_MODULE, GPIO_KEY_NAME); if(IS_ERR(kobox_key_class)) { printk("class_create failed!\n"); goto fail; } /* create /dev/kobox_gpio */ pstdev = device_create(kobox_key_class, NULL, MKDEV(major, 0), NULL, GPIO_KEY_NAME); if(!pstdev) { printk("device_create failed!\n"); goto fail1; } /* set gpf0/1/2/4 as extern interrupt pins */ set_gpio_as_eint(); request_irq_for_gpio(); printk("#####key_drv_init ok!\n"); return 0; fail1: class_destroy(kobox_key_class); fail: unregister_chrdev(major, GPIO_KEY_NAME); return -1; } void __exit key_drv_exit(void) { printk("exit gpio drv!\n"); device_destroy(kobox_key_class, MKDEV(major, 0)); class_destroy(kobox_key_class); unregister_chrdev(major, GPIO_KEY_NAME); return; } module_init(key_drv_init); module_exit(key_drv_exit);
[\u@\h \W]# insmod key.ko
#####enter key_drv_init!
[func:request_irq_for_gpio][line:278] request_irq ok, irq:17!
[func:request_irq_for_gpio][line:298] request_irq ok, irq:52!
[func:request_irq_for_gpio][line:316] request_irq ok, irq:18!
[func:request_irq_for_gpio][line:333] request_irq ok, irq:16!
#####key_drv_init ok!
[\u@\h \W]# ls
key.ko
[\u@\h \W]# cat /proc/interrupts
CPU0
16: 0 s3c-ext0 0 key4
17: 0 s3c-ext0 1 key1
18: 0 s3c-ext0 2 key3
24: 0 s3c 8 s3c2410-rtc tick
29: 10767 s3c 13 samsung_time_irq
32: 0 s3c 16 s3c2410-lcd
37: 0 s3c 21 s3c-mci
42: 0 s3c 26 ohci_hcd:usb1
43: 0 s3c 27 s3c2440-i2c.0
46: 0 s3c 30 s3c2410-rtc alarm
52: 0 s3c-ext 4 key2
55: 512 s3c-ext 7 eth0
64: 0 s3c-ext 16 s3c-mci
74: 69 s3c-level 0 s3c2440-uart
75: 523 s3c-level 1 s3c2440-uart
87: 0 s3c-level 13 s3c2410-wdt
Err: 0
[\u@\h \W]#
按四个按键打印:
irq = 18
irq = 17
irq = 16
irq = 16
irq = 52
irq = 52
irq = 52
irq = 52
irq = 52
irq = 52
irq = 52
irq = 18
irq = 17
irq = 16