作者

彭東林

前面我們實現了一種設備樹下中斷的使用方法,下面介紹第二種,這種方式本質上跟前者是一樣的,使用的是platform_bus的接口。

爲了便於比較,還是以底板上面上的四個按鍵爲例分析,其中前兩個按鍵使用第二種方式,後兩個按鍵使用第一種方式。

正文

原理圖可以參考博文:基於tiny4412的Linux內核移植--- 中斷和GPIO學習(1)

下面是設備樹的改動:



1 diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
2 index 610202a..2e69c91 100644
3 --- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
4 +++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
5 @@ -16,6 +16,7 @@
6 #include <dt-bindings/gpio/gpio.h>
7 #include <dt-bindings/usb4640/usb4640.h>
8 #include <dt-bindings/pwm/pwm.h>
9 +#include <dt-bindings/interrupt-controller/irq.h>
10 #include <autoconf.h>
11
12 / {
13 @@ -136,6 +137,14 @@
14 };
15 };
16 #endif
17 +
18 +interrupt_another: interrupt_another {
19 + compatible = "tiny4412,interrupt_another";
20 + interrupt-parent = <&gpx3>;
21 + interrupts = <2 IRQ_TYPE_EDGE_FALLING 3 IRQ_TYPE_EDGE_FALLING>;
22 + tiny4412,int_gpio0 = <&gpx3 4 GPIO_ACTIVE_HIGH>;
23 + tiny4412,int_gpio1 = <&gpx3 5 GPIO_ACTIVE_HIGH>;
24 + };
25 };
26
27 &rtc {


 其中,interrupts屬性值的解析需要看中斷控制器gpx3在創建irq_domain時設置的回調函數exynos_eint_irqd_ops的xlate成員。以後我們再分析。而gpio屬性的值的含義則需要看gpio控制器gpx3在創建時設置的of_xlate回調函數of_gpio_simple_xlate,這個以後分析。

下面看驅動:



1 #include <linux/init.h>
2 #include <linux/module.h>
3 #include <linux/platform_device.h>
4 #include <linux/gpio.h>
5 #include <linux/of.h>
6 #include <linux/of_gpio.h>
7 #include <linux/interrupt.h>
8
9 typedef struct
10 {
11 int gpio;
12 int irq;
13 char name[20];
14 }int_demo_data_t;
15
16 static irqreturn_t int_demo_isr_pdev(int irq, void *dev_id)
17 {
18 int_demo_data_t *data = dev_id;
19
20 printk("%s enter, %s irq: %d\n", __func__, data->name, irq);
21
22 return IRQ_HANDLED;
23 }
24
25 static irqreturn_t int_demo_isr_gpio(int irq, void *dev_id)
26 {
27 int_demo_data_t *data = dev_id;
28
29 printk("%s enter, %s irq: %d\n", __func__, data->name, irq);
30 return IRQ_HANDLED;
31 }
32
33 static int int_demo_probe(struct platform_device *pdev) {
34 struct device *dev = &pdev->dev;
35 int irq_gpio = -1;
36 int irq = -1;
37 int ret = 0;
38 int i = 0;
39 int_demo_data_t *data = NULL;
40
41 printk("%s enter.\n", __func__);
42
43 if (!dev->of_node) {
44 dev_err(dev, "no platform data.\n");
45 goto err0;
46 }
47
48 data = devm_kmalloc(dev, sizeof(*data)*4, GFP_KERNEL);
49 if (!data) {
50 dev_err(dev, "no memory.\n");
51 goto err0;
52 }
53
54 for (i = 0; i < 2; i++) {
55 irq = platform_get_irq(pdev, i);
56 sprintf(data[i].name, "tiny4412,pdev_irq_%d", i);
57 ret = devm_request_any_context_irq(dev, irq,
58 int_demo_isr_pdev, IRQF_TRIGGER_FALLING, data[i].name, data+i);
59 if (ret < 0) {
60 dev_err(dev, "Unable to claim irq %d; error %d\n",
61 irq, ret);
62 goto err0;
63 }
64 printk("request irq: %d\n", irq);
65 }
66
67 for (i = 0; i < 2; i++) {
68 sprintf(data[i+2].name, "tiny4412,int_gpio%d", i);
69 irq_gpio = of_get_named_gpio(dev->of_node,
70 data[i+2].name, 0);
71 if (irq_gpio < 0) {
72 dev_err(dev, "Looking up %s property in node %s failed %d\n",
73 data[i].name, dev->of_node->full_name, irq_gpio);
74 goto err0;
75 }
76
77 data[i+2].gpio = irq_gpio;
78
79 irq = gpio_to_irq(irq_gpio);
80 if (irq < 0) {
81 dev_err(dev,
82 "Unable to get irq number for GPIO %d, error %d\n",
83 irq_gpio, irq);
84 goto err0;
85 }
86
87 data[i+2].irq = irq;
88
89 printk("%s: gpio: %d ---> irq (%d)\n", __func__, irq_gpio, irq);
90
91 ret = devm_request_any_context_irq(dev, irq,
92 int_demo_isr_gpio, IRQF_TRIGGER_FALLING, data[i+2].name, data+i+2);
93 if (ret < 0) {
94 dev_err(dev, "Unable to claim irq %d; error %d\n",
95 irq, ret);
96 goto err0;
97 }
98 }
99
100
101 return 0;
102
103 err0:
104 return -EINVAL;
105 }
106
107 static int int_demo_remove(struct platform_device *pdev) {
108
109 printk("%s enter.\n", __func__);
110 return 0;
111 }
112
113 static const struct of_device_id int_demo_dt_ids[] = {
114 { .compatible = "tiny4412,interrupt_another", },
115 {},
116 };
117
118 MODULE_DEVICE_TABLE(of, int_demo_dt_ids);
119
120 static struct platform_driver int_demo_driver = {
121 .driver = {
122 .name = "interrupt_another",
123 .of_match_table = of_match_ptr(int_demo_dt_ids),
124 },
125 .probe = int_demo_probe,
126 .remove = int_demo_remove,
127 };
128
129 static int __init int_demo_init(void)
130 {
131 int ret;
132
133 ret = platform_driver_register(&int_demo_driver);
134 if (ret)
135 printk(KERN_ERR "int demo: probe failed: %d\n", ret);
136
137 return ret;
138 }
139 module_init(int_demo_init);
140
141 static void __exit int_demo_exit(void)
142 {
143 platform_driver_unregister(&int_demo_driver);
144 }
145 module_exit(int_demo_exit);
146
147 MODULE_LICENSE("GPL");


在platform_device進行populate的時候,已經對其irq資源進行了映射,這個以後分析。

驗證

加載驅動:



[root@tiny4412 mnt]# insmod interrupt_another.ko 
[ 33.330879] int_demo_probe enter.
[ 33.331896] request irq: 103
[ 33.332778] request irq: 104
[ 33.333412] int_demo_probe: gpio: 240 ---> irq (107)
[ 33.334535] int_demo_probe: gpio: 241 ---> irq (108)


依次按鍵,由於沒有加消抖處理,所以依次按鍵可能會觸發多次中斷



[root@tiny4412 mnt]# [ 1244.082303] int_demo_isr_pdev enter, tiny4412,pdev_irq_0 irq: 103
[ 1244.229761] int_demo_isr_pdev enter, tiny4412,pdev_irq_0 irq: 103
[ 1245.129735] int_demo_isr_pdev enter, tiny4412,pdev_irq_1 irq: 104
[ 1245.283928] int_demo_isr_pdev enter, tiny4412,pdev_irq_1 irq: 104
[ 1246.269231] int_demo_isr_gpio enter, tiny4412,int_gpio0 irq: 107
[ 1246.476101] int_demo_isr_gpio enter, tiny4412,int_gpio0 irq: 107
[ 1247.769903] int_demo_isr_gpio enter, tiny4412,int_gpio1 irq: 108
[ 1248.034338] int_demo_isr_gpio enter, tiny4412,int_gpio1 irq: 108
[ 1248.035396] int_demo_isr_gpio enter, tiny4412,int_gpio1 irq: 108
[ 1248.035858] int_demo_isr_gpio enter, tiny4412,int_gpio1 irq: 108
[ 1248.036218] int_demo_isr_gpio enter, tiny4412,int_gpio1 irq: 108


我們再看看系統中斷資源註冊情況



[root@tiny4412 mnt]# cat /proc/interrupts 
CPU0 CPU1 CPU2 CPU3
36: 0 0 0 0 GIC 89 Edge mct_comp_irq
37: 16511 8820 5442 861 GIC 28 Edge MCT
42: 0 0 0 0 PMU 44 Edge s3c2410-rtc alarm
43: 0 0 0 0 PMU 45 Edge s3c2410-rtc tick
44: 34 0 0 0 GIC 107 Edge mmc0
45: 1 0 0 0 GIC 103 Edge 12480000.hsotg, 12480000.hsotg, dwc2_hsotg:usb1
46: 811 0 0 0 GIC 102 Edge ehci_hcd:usb2, ohci_hcd:usb3
47: 380 0 0 0 GIC 84 Edge 13800000.serial
51: 72 0 0 0 GIC 93 Edge 13890000.i2c
57: 1 0 0 0 GIC 67 Edge 12680000.pdma
58: 0 0 0 0 GIC 68 Edge 12690000.pdma
59: 0 0 0 0 GIC 66 Edge 12850000.mdma
71: 0 0 0 0 GIC 79 Edge 11400000.pinctrl
72: 1 0 0 0 GIC 78 Edge 11000000.pinctrl
90: 0 0 0 0 COMBINER 80 Edge 3860000.pinctrl
91: 0 0 0 0 GIC 104 Edge 106e0000.pinctrl
95: 47 0 0 0 GIC 109 Edge dw-mci
103: 8 0 0 0 exynos4210_wkup_irq_chip 2 Edge tiny4412,pdev_irq_0
104: 4 0 0 0 exynos4210_wkup_irq_chip 3 Edge tiny4412,pdev_irq_1
105: 6 0 0 0 exynos4210_wkup_irq_chip 1 Edge mma7660
106: 1 0 0 0 exynos_gpio_irq_chip 2 Edge 12530000.sdhci cd
107: 6 0 0 0 exynos4210_wkup_irq_chip 4 Edge tiny4412,int_gpio0
108: 9 0 0 0 exynos4210_wkup_irq_chip 5 Edge tiny4412,int_gpio1
IPI0: 0 1 1 1 CPU wakeup interrupts
IPI1: 0 0 0 0 Timer broadcast interrupts
IPI2: 841 1545 682 838 Rescheduling interrupts
IPI3: 1 3 2 3 Function call interrupts
IPI4: 0 1 1 1 Single function call interrupts
IPI5: 0 0 0 0 CPU stop interrupts
IPI6: 0 0 0 0 IRQ work interrupts
IPI7: 0 0 0 0 completion interrupts


 

未完待續...