历史上的今天
今天是:2025年02月17日(星期一)
2020年02月17日 | 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(1)
2020-02-17 来源:eefocus
平臺
tiny4412 ADK
Linux-4.4.4
u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uImage做了稍許改動
概述
這篇博客以一個簡單的按鍵中斷來演示一下有了設備樹後的中斷的使用,其中涉及到新版kernel的pinctrl和gpio子系統。
在tiny4412的底板上有四個key,如下:
上圖中,在沒有按鍵的時候,對應的GPIO是被拉高的,當按下鍵的時候,對應的GPIO被拉低,從而產生一個下降沿中斷。
有了上面的準備,首先我們需要修改設備樹,添加相應的節點和相關的屬性:
1 diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
2 index 610202a..a130047 100644
3 --- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
4 +++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
5 @@ -136,6 +136,14 @@
6 };
7 };
8 #endif
9 +
10 + interrupt_demo: interrupt_demo {
11 + compatible = "tiny4412,interrupt_demo";
12 + tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>;
13 + tiny4412,int_gpio2 = <&gpx3 3 GPIO_ACTIVE_HIGH>;
14 + tiny4412,int_gpio3 = <&gpx3 4 GPIO_ACTIVE_HIGH>;
15 + tiny4412,int_gpio4 = <&gpx3 5 GPIO_ACTIVE_HIGH>;
16 + };
17 };
上面的代碼中,我們添加了四個屬性,對應的就是那四個key對應的gpio,參考gpx3的實現(exynos4x12-pinctrl.dtsi):
gpx3: gpx3 {
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
可以看到,gpx3含有gpio-controller和interrupt-controller屬性,表示它是一個gpio控制器和中斷控制器,它的gpio-cell爲2,意味着應該給這個gpx3傳遞兩個參數,以
tiny4412,int_gpio1 = <&gpx3 2 GPIO_ACTIVE_HIGH>
爲例,這兩個參數就是2和GPIO_ACTIVE_HIGH,如果參數不對的話,比如只傳了一個參數2,那麼在調用of_get_named_gpio會出現如下錯誤:
[ 31.133799] /interrupt_demo: arguments longer than property
[ 31.133935] interrupt_demo interrupt_demo: Looking up tiny4412,int_gpio4 property in node /interrupt_demo failed -22
[ 31.144562] interrupt_demo: probe of interrupt_demo failed with error -22
使用 make dtbs 編譯完設備樹。
在Samsung的pinctrl驅動中加一些log:
@@ -622,6 +626,8 @@ static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
unsigned int virq;
+ printk("%s enter.n", __func__);
+
if (!bank->irq_domain)
return -ENXIO;
然後我們編寫對應的驅動程序:
1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 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(int irq, void *dev_id) 17 { 18 int_demo_data_t *data = dev_id; 19 20 printk("%s enter, %s: gpio:%d, irq: %dn", __func__, data->name, data->gpio, data->irq); 21 22 return IRQ_HANDLED; 23 } 24 25 static int int_demo_probe(struct platform_device *pdev) { 26 struct device *dev = &pdev->dev; 27 int irq_gpio = -1; 28 int irq = -1; 29 int ret = 0; 30 int i = 0; 31 int_demo_data_t *data = NULL; 32 33 printk("%s enter.n", __func__); 34 35 if (!dev->of_node) { 36 dev_err(dev, "no platform data.n"); 37 goto err1; 38 } 39 40 data = devm_kmalloc(dev, sizeof(*data)*4, GFP_KERNEL); 41 if (!data) { 42 dev_err(dev, "no memory.n"); 43 goto err0; 44 } 45 46 #if 0 47 for (i = 3; i >= 0; i--) { 48 sprintf(data[i].name, "tiny4412,int_gpio%d", i+1); 49 #else 50 for (i = 0; i < 4; i++) { 51 #endif 52 irq_gpio = of_get_named_gpio(dev->of_node, 53 data[i].name, 0); 54 if (irq_gpio < 0) { 55 dev_err(dev, "Looking up %s property in node %s failed %dn", 56 data[i].name, dev->of_node->full_name, irq_gpio); 57 goto err1; 58 } 59 60 data[i].gpio = irq_gpio; 61 62 irq = gpio_to_irq(irq_gpio); 63 if (irq < 0) { 64 dev_err(dev, 65 "Unable to get irq number for GPIO %d, error %dn", 66 irq_gpio, irq); 67 goto err1; 68 } 69 70 data[i].irq = irq; 71 72 printk("%s: gpio: %d ---> irq (%d)n", __func__, irq_gpio, irq); 73 74 ret = devm_request_any_context_irq(dev, irq, 75 int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i); 76 if (ret < 0) { 77 dev_err(dev, "Unable to claim irq %d; error %dn", 78 irq, ret); 79 goto err1; 80 } 81 } 82 83 return 0; 84 85 err1: 86 devm_kfree(dev, data); 87 err0: 88 return -EINVAL; 89 } 90 91 static int int_demo_remove(struct platform_device *pdev) { 92 93 printk("%s enter.n", __func__); 94 95 return 0; 96 } 97 98 static const struct of_device_id int_demo_dt_ids[] = { 99 { .compatible = "tiny4412,interrupt_demo", }, 100 {}, 101 }; 102 103 MODULE_DEVICE_TABLE(of, int_demo_dt_ids); 104 105 static struct platform_driver int_demo_driver = { 106 .driver = { 107 .name = "interrupt_demo", 108 .of_match_table = of_match_ptr(int_demo_dt_ids), 109 }, 110 .probe = int_demo_probe, 111 .remove = int_demo_remove, 112 }; 113 114 static int __init int_demo_init(void) 115 { 116 int ret; 117 118 ret = platform_driver_register(&int_demo_driver); 119 if (ret) 120 printk(KERN_ERR "int demo: probe failed: %dn", ret); 121 122 return ret; 123 } 124 module_init(int_demo_init); 125 126 static void __exit int_demo_exit(void) 127 { 128 platform_driver_unregister(&int_demo_driver); 129 } 130 module_exit(int_demo_exit); 131 132 MODULE_LICENSE("GPL"); 編譯驅動後,將ko文件拷貝到nfs目錄下,然後在開發板上執行 mount -t nfs -o nolock 192.168.2.6:/nfsroot /mnt 將共享目錄從PC上掛載到開發板上,然後insmod這個驅動: [root@tiny4412 ]# mount -t nfs -o nolock 192.168.2.6:/nfsroot /mnt [root@tiny4412 ]# cd /mnt [root@tiny4412 mnt]# ls fdt interrupt_demo.ko tiny4412.dts [root@tiny4412 mnt]# insmod interrupt_demo.ko [ 1655.872546] int_demo_probe enter. [ 1655.872841] samsung_gpio_to_irq enter. [ 1655.873061] int_demo_probe: gpio: 238 ---> irq (105) [ 1655.873716] samsung_gpio_to_irq enter. [ 1655.873906] int_demo_probe: gpio: 239 ---> irq (106) [ 1655.874424] samsung_gpio_to_irq enter. [ 1655.874773] int_demo_probe: gpio: 240 ---> irq (107) [ 1655.879981] samsung_gpio_to_irq enter. [ 1655.883485] int_demo_probe: gpio: 241 ---> irq (108) [root@tiny4412 mnt]# // 然後我們嘗試按底板上的按鍵,會看到相應的中斷log [root@tiny4412 mnt]# [ 33.462207] int_demo_isr enter, tiny4412,int_gpio1: gpio:238, irq: 105 [ 33.657304] int_demo_isr enter, tiny4412,int_gpio1: gpio:238, irq: 105 [ 35.769955] int_demo_isr enter, tiny4412,int_gpio3: gpio:240, irq: 107 [ 35.951373] int_demo_isr enter, tiny4412,int_gpio3: gpio:240, irq: 107 [ 36.525804] int_demo_isr enter, tiny4412,int_gpio4: gpio:241, irq: 108 [ 36.698501] int_demo_isr enter, tiny4412,int_gpio4: gpio:241, irq: 108 [ 41.710481] int_demo_isr enter, tiny4412,int_gpio2: gpio:239, irq: 106 [ 41.857190] int_demo_isr enter, tiny4412,int_gpio2: gpio:239, irq: 106
史海拾趣
|
ACDBUF是一个int型十六进制数最大为0xfff。 a=ADCBUF & 0XF00 >>8; b=ADCBUF & 0X0F0 >>4; c=ADCBUF & 0X00F; a=a&0x08*8+a&0x04*4+a&0x02*2+a&0x01;a=a*256; b=b&0x08*8+b& ...… 查看全部问答> |
|
我wince5.0下执行CamTest2.exe(厂家提供的camer测试程序),弹出如下对话框。 This test program only supports MJPEG stream formats. the driver reports format 5 supported . 请问MJPEG对应在PB下需要添加哪几个组件?? 驱动是厂家提供的 ...… 查看全部问答> |
|
我按照网络上的方法来修改IP地址,为什么老是不行,虽然程序执行成功,该添加的注册表项也添加了,但是为什么老是改不成功呢? 我用的方法如下: HKEY hkey; CString strKeyName &nbs ...… 查看全部问答> |
|
请问能够通过I2S音频解码芯片进行ADC转换,再通过I2S接口回传至2440处理器吗?如何操作? 音频芯片AK4554自带I2S接口,以及两路ADC转换,默认ADC一直工作,是否ADC的数据直接送到 了I2S的SDO口?将SDO口接到2440的SDI口,通过寄存器能读出ADC转换 ...… 查看全部问答> |




