基於tiny4412的Linux內核移植--- 中斷和GPIO學習(3)
作者
彭東林
pengdonglin137@163.com
平臺
tiny4412 ADK
Linux-4.4.4
u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uImage做了稍許改動
簡介
前面我們實現了一種設備樹下中斷的使用方法,下面介紹第二種,這種方式本質上跟前者是一樣的,使用的是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
未完待續...
本文来自博客园,作者:摩斯电码,未经同意,禁止转载