作者

彭東林

pengdonglin137@163.com

平臺

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
  3. --- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
  4. +++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
  5. @@ -, +, @@
  6. };
  7. };
  8. #endif
  9. +
  10. + interrupt_demo: interrupt_demo {
  11. + compatible = "tiny4412,interrupt_demo";
  12. + tiny4412,int_gpio1 = <&gpx3 GPIO_ACTIVE_HIGH>;
  13. + tiny4412,int_gpio2 = <&gpx3 GPIO_ACTIVE_HIGH>;
  14. + tiny4412,int_gpio3 = <&gpx3 GPIO_ACTIVE_HIGH>;
  15. + tiny4412,int_gpio4 = <&gpx3 GPIO_ACTIVE_HIGH>;
  16. + };
  17. };

上面的代碼中,我們添加了四個屬性,對應的就是那四個key對應的gpio,參考gpx3的實現(exynos4x12-pinctrl.dtsi):

  1. gpx3: gpx3 {
  2. gpio-controller;
  3. #gpio-cells = <>;
  4.  
  5. interrupt-controller;
  6. #interrupt-cells = <>;
  7. };

可以看到,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會出現如下錯誤:

  1. [ 31.133799] /interrupt_demo: arguments longer than property
  2. [ 31.133935] interrupt_demo interrupt_demo: Looking up tiny4412,int_gpio4 property in node /interrupt_demo failed -
  3. [ 31.144562] interrupt_demo: probe of interrupt_demo failed with error -

使用 make dtbs 編譯完設備樹。

在Samsung的pinctrl驅動中加一些log:

  1. @@ -, +, @@ static int samsung_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
  2. struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
  3. unsigned int virq;
  4.  
  5. + printk("%s enter.\n", __func__);
  6. +
  7. if (!bank->irq_domain)
  8. return -ENXIO;

然後我們編寫對應的驅動程序:

  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[];
  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: %d\n", __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 = -;
  28. int irq = -;
  29. int ret = ;
  30. int i = ;
  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)*, GFP_KERNEL);
  41. if (!data) {
  42. dev_err(dev, "no memory.\n");
  43. goto err0;
  44. }
  45.  
  46. #if 0
  47. for (i = ; i >= ; i--) {
  48. sprintf(data[i].name, "tiny4412,int_gpio%d", i+);
  49. #else
  50. for (i = ; i < ; i++) {
  51. #endif
  52. irq_gpio = of_get_named_gpio(dev->of_node,
  53. data[i].name, );
  54. if (irq_gpio < ) {
  55. dev_err(dev, "Looking up %s property in node %s failed %d\n",
  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 < ) {
  64. dev_err(dev,
  65. "Unable to get irq number for GPIO %d, error %d\n",
  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 < ) {
  77. dev_err(dev, "Unable to claim irq %d; error %d\n",
  78. irq, ret);
  79. goto err1;
  80. }
  81. }
  82.  
  83. return ;
  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 ;
  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: %d\n", 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這個驅動:

  1. [root@tiny4412 ]# mount -t nfs -o nolock 192.168.2.6:/nfsroot /mnt
  2. [root@tiny4412 ]# cd /mnt
  3. [root@tiny4412 mnt]# ls
  4. fdt interrupt_demo.ko tiny4412.dts
  5. [root@tiny4412 mnt]# insmod interrupt_demo.ko
  6. [ 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)
  7. [root@tiny4412 mnt]#
    // 然後我們嘗試按底板上的按鍵,會看到相應的中斷log
  8. [root@tiny4412 mnt]# [ 33.462207] int_demo_isr enter, tiny4412,int_gpio1: gpio:, irq:
  9. [ 33.657304] int_demo_isr enter, tiny4412,int_gpio1: gpio:, irq:
  10. [ 35.769955] int_demo_isr enter, tiny4412,int_gpio3: gpio:, irq:
  11. [ 35.951373] int_demo_isr enter, tiny4412,int_gpio3: gpio:, irq:
  12. [ 36.525804] int_demo_isr enter, tiny4412,int_gpio4: gpio:, irq:
  13. [ 36.698501] int_demo_isr enter, tiny4412,int_gpio4: gpio:, irq:
  14. [ 41.710481] int_demo_isr enter, tiny4412,int_gpio2: gpio:, irq:
  15. [ 41.857190] int_demo_isr enter, tiny4412,int_gpio2: gpio:, irq:
  16.  
  17. [root@tiny4412 mnt]# cat /proc/interrupts
  18. CPU0 CPU1 CPU2 CPU3
  19. : GIC Edge mct_comp_irq
  20. : GIC Edge MCT
  21. : GIC Edge mmc0
  22. : GIC Edge .hsotg, .hsotg, dwc2_hsotg:usb1
  23. : GIC Edge ehci_hcd:usb2, ohci_hcd:usb3
  24. : GIC Edge .serial
  25. : GIC Edge .i2c
  26. : GIC Edge .pdma
  27. : GIC Edge .pdma
  28. : GIC Edge .mdma
  29. : GIC Edge .pinctrl
  30. : GIC Edge .pinctrl
  31. : COMBINER Edge .pinctrl
  32. : GIC Edge 106e0000.pinctrl
  33. : GIC Edge dw-mci
  34. : exynos4210_wkup_irq_chip Edge mma7660
  35. : exynos_gpio_irq_chip Edge .sdhci cd
  36. : exynos4210_wkup_irq_chip Edge tiny4412,int_gpio1
  37. : exynos4210_wkup_irq_chip Edge tiny4412,int_gpio2
  38. : exynos4210_wkup_irq_chip Edge tiny4412,int_gpio3
  39. : exynos4210_wkup_irq_chip Edge tiny4412,int_gpio4
  40. IPI0: CPU wakeup interrupts
  41. IPI1: Timer broadcast interrupts
  42. IPI2: Rescheduling interrupts
  43. IPI3: Function call interrupts
  44. IPI4: Single function call interrupts
  45. IPI5: CPU stop interrupts
  46. IPI6: IRQ work interrupts
  47. IPI7: completion interrupts
  48. Err:

如果我們修改驅動驅動,改變一下中斷的申請順序,然後重啓系統(測試發現,如果不重啓系統,而是重新加載新的驅動,gpio跟irq的對應關系沒有發生改變)

  1. #if 1
  2. for (i = ; i >= ; i--) {
  3. sprintf(data[i].name, "tiny4412,int_gpio%d", i+);
  4. #else
  5. for (i = ; i < ; i++) {
  6. #endif

此時,會看到如下的log:

  1. [root@tiny4412 mnt]# insmod interrupt_demo.ko
  2. [  119.735726] int_demo_probe enter.
    [  119.736295] samsung_gpio_to_irq enter.
    [  119.736417] int_demo_probe: gpio: 241 ---> irq (105)
    [  119.736852] samsung_gpio_to_irq enter.
    [  119.736985] int_demo_probe: gpio: 240 ---> irq (106)
    [  119.737254] samsung_gpio_to_irq enter.
    [  119.737893] int_demo_probe: gpio: 239 ---> irq (107)
    [  119.743029] samsung_gpio_to_irq enter.
    [  119.746631] int_demo_probe: gpio: 238 ---> irq (108)
  3. [root@tiny4412 mnt]# cat /proc/interrupts
  4. CPU0 CPU1 CPU2 CPU3
  5. : GIC Edge mct_comp_irq
  6. : GIC Edge MCT
  7. ... ...
  8. : exynos4210_wkup_irq_chip Edge tiny4412,int_gpio4
  9. : exynos4210_wkup_irq_chip Edge tiny4412,int_gpio3
  10. : exynos4210_wkup_irq_chip Edge tiny4412,int_gpio2
  11. : exynos4210_wkup_irq_chip Edge tiny4412,int_gpio1
  12. ... ...

未完待續... ...

基於tiny4412的Linux內核移植--- 中斷和GPIO學習(1)的更多相关文章

  1. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(3)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  2. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(2)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  3. 基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(2)

    作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台 tiny4412 ADK Linux-4.9 概述 前面一篇博文基於tiny4412的Linux內核移 ...

  4. 基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(1)

    作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台 tiny4412 ADK Linux-4.9 概述 前面几篇博文列举了在有设备树的时候,gpio中断的 ...

  5. Linux內核中常用的一些延時方法

    Linux內核中常用的一些延時方法 這些方法在以下路徑下定義:kernel/include/linux/delay.h #ifndef _LINUX_DELAY_H #define _LINUX_DE ...

  6. 【转】Linux內核驅動之GPIO子系統(一)GPIO的使用 _蝸牛

    原文网址:http://tc.chinawin.net/it/os/article-2512b.html 一 概述 Linux內核中gpio是最簡單,最常用的資源(和interrupt ,dma,ti ...

  7. 無心插柳的Linux學習者代言人——蔡德明

    誰是「蔡德明」恐怕沒有多少人知道,不過提到「鳥哥」這個稱號,在臺灣的Linux社群幾乎是無人不知無人不曉,蔡德明正是鳥哥的本名.鳥哥究竟多有名? 如果你是有意學習Linux的初學者,卻不知如何下手,1 ...

  8. 第一章 Linux內核簡介

    1. Linux是類Unix系統,但他不是Unix. 儘管Linux借鑑了Unix的許多設計並且實現了Unix的API(由Posix標準和其他Single Unix Specification定義的) ...

  9. 基于tiny4412的Linux内核移植 ---- 調試方法

    作者信息 彭東林 郵箱: pengdonglin137@163.com 平臺 Linux-4.4.4 uboot使用的是友善自帶的(爲了支持uImage和設備樹做了稍許修改) 概述 這篇博客主要用於匯 ...

随机推荐

  1. 探究javascript对象和数组的异同,及函数变量缓存技巧

    javascript中最经典也最受非议的一句话就是:javascript中一切皆是对象.这篇重点要提到的,就是任何jser都不陌生的Object和Array. 有段时间曾经很诧异,到底两种数据类型用来 ...

  2. Cassandra简介

    在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了一种非常流行的图形数据库Neo4J的使用方法.而在本文中,我们将对另外一种类型的NoSQL数据库——Cassandra进行简单地介 ...

  3. [原创]mybatis中整合ehcache缓存框架的使用

    mybatis整合ehcache缓存框架的使用 mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓 ...

  4. ExtJS 4.2 Grid组件的单元格合并

    ExtJS 4.2 Grid组件本身并没有提供单元格合并功能,需要自己实现这个功能. 目录 1. 原理 2. 多列合并 3. 代码与在线演示 1. 原理 1.1 HTML代码分析 首先创建一个Grid ...

  5. 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)

    书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...

  6. vue.js学习笔记

    有了孩子之后,元旦就哪也去不了了(孩子太小),刚好利用一些时间,来公司充充电补补课,学习学习新技术,在这里做一个整理和总结.(选择的东西,既然热爱就把他做好吧!). 下来进入咱们的学习环节: 一.从H ...

  7. 一个诡异的COOKIE问题

    今天下午,发现本地的测试环境突然跑不动了,thinkphp直接跑到异常页面,按照正常的排错思路,直接看thinkphp的log 有一条 [ error ] [2]setcookie() expects ...

  8. 总结iOS开发中的断点续传那些事儿

    前言 断点续传概述 断点续传就是从文件赏赐中断的地方重新开始下载或者上传数据,而不是从头文件开始.当下载大文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会从头下载,这样很 ...

  9. 【代码笔记】iOS-获得当前的月的天数

    一,代码. #import "ViewController.h" @interface ViewController () @end @implementation ViewCon ...

  10. 监控 SQL Server (2005/2008) 的运行状况

    Microsoft SQL Server 2005 提供了一些工具来监控数据库.方法之一是动态管理视图.动态管理视图 (DMV) 和动态管理函数 (DMF) 返回的服务器状态信息可用于监控服务器实例的 ...