基於tiny4412的Linux內核移植--- 中斷和GPIO學習(1)
作者
彭東林
pengdonglin137@163.com
平臺
tiny4412 ADK
Linux-4.4.4
u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uImage做了稍許改動
概述
這篇博客以一個簡單的按鍵中斷來演示一下有了設備樹後的中斷的使用,其中涉及到新版kernel的pinctrl和gpio子系統。
正文
在tiny4412的底板上有四個key,如下:
上圖中,在沒有按鍵的時候,對應的GPIO是被拉高的,當按下鍵的時候,對應的GPIO被拉低,從而產生一個下降沿中斷。
有了上面的準備,首先我們需要修改設備樹,添加相應的節點和相關的屬性:
diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
index 610202a..a130047
--- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
+++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
@@ -, +, @@
};
};
#endif
+
+ interrupt_demo: interrupt_demo {
+ compatible = "tiny4412,interrupt_demo";
+ tiny4412,int_gpio1 = <&gpx3 GPIO_ACTIVE_HIGH>;
+ tiny4412,int_gpio2 = <&gpx3 GPIO_ACTIVE_HIGH>;
+ tiny4412,int_gpio3 = <&gpx3 GPIO_ACTIVE_HIGH>;
+ tiny4412,int_gpio4 = <&gpx3 GPIO_ACTIVE_HIGH>;
+ };
};
上面的代碼中,我們添加了四個屬性,對應的就是那四個key對應的gpio,參考gpx3的實現(exynos4x12-pinctrl.dtsi):
gpx3: gpx3 {
gpio-controller;
#gpio-cells = <>;
interrupt-controller;
#interrupt-cells = <>;
};
可以看到,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 -
[ 31.144562] interrupt_demo: probe of interrupt_demo failed with error -
使用 make dtbs 編譯完設備樹。
在Samsung的pinctrl驅動中加一些log:
@@ -, +, @@ 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;
然後我們編寫對應的驅動程序:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/interrupt.h> typedef struct
{
int gpio;
int irq;
char name[];
}int_demo_data_t; static irqreturn_t int_demo_isr(int irq, void *dev_id)
{
int_demo_data_t *data = dev_id; printk("%s enter, %s: gpio:%d, irq: %d\n", __func__, data->name, data->gpio, data->irq); return IRQ_HANDLED;
} static int int_demo_probe(struct platform_device *pdev) {
struct device *dev = &pdev->dev;
int irq_gpio = -;
int irq = -;
int ret = ;
int i = ;
int_demo_data_t *data = NULL; printk("%s enter.\n", __func__); if (!dev->of_node) {
dev_err(dev, "no platform data.\n");
goto err1;
} data = devm_kmalloc(dev, sizeof(*data)*, GFP_KERNEL);
if (!data) {
dev_err(dev, "no memory.\n");
goto err0;
} #if 0
for (i = ; i >= ; i--) {
sprintf(data[i].name, "tiny4412,int_gpio%d", i+);
#else
for (i = ; i < ; i++) {
#endif
irq_gpio = of_get_named_gpio(dev->of_node,
data[i].name, );
if (irq_gpio < ) {
dev_err(dev, "Looking up %s property in node %s failed %d\n",
data[i].name, dev->of_node->full_name, irq_gpio);
goto err1;
} data[i].gpio = irq_gpio; irq = gpio_to_irq(irq_gpio);
if (irq < ) {
dev_err(dev,
"Unable to get irq number for GPIO %d, error %d\n",
irq_gpio, irq);
goto err1;
} data[i].irq = irq; printk("%s: gpio: %d ---> irq (%d)\n", __func__, irq_gpio, irq); ret = devm_request_any_context_irq(dev, irq,
int_demo_isr, IRQF_TRIGGER_FALLING, data[i].name, data+i);
if (ret < ) {
dev_err(dev, "Unable to claim irq %d; error %d\n",
irq, ret);
goto err1;
}
} return ; err1:
devm_kfree(dev, data);
err0:
return -EINVAL;
} static int int_demo_remove(struct platform_device *pdev) { printk("%s enter.\n", __func__); return ;
} static const struct of_device_id int_demo_dt_ids[] = {
{ .compatible = "tiny4412,interrupt_demo", },
{},
}; MODULE_DEVICE_TABLE(of, int_demo_dt_ids); static struct platform_driver int_demo_driver = {
.driver = {
.name = "interrupt_demo",
.of_match_table = of_match_ptr(int_demo_dt_ids),
},
.probe = int_demo_probe,
.remove = int_demo_remove,
}; static int __init int_demo_init(void)
{
int ret; ret = platform_driver_register(&int_demo_driver);
if (ret)
printk(KERN_ERR "int demo: probe failed: %d\n", ret); return ret;
}
module_init(int_demo_init); static void __exit int_demo_exit(void)
{
platform_driver_unregister(&int_demo_driver);
}
module_exit(int_demo_exit); 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:, irq:
[ 33.657304] int_demo_isr enter, tiny4412,int_gpio1: gpio:, irq:
[ 35.769955] int_demo_isr enter, tiny4412,int_gpio3: gpio:, irq:
[ 35.951373] int_demo_isr enter, tiny4412,int_gpio3: gpio:, irq:
[ 36.525804] int_demo_isr enter, tiny4412,int_gpio4: gpio:, irq:
[ 36.698501] int_demo_isr enter, tiny4412,int_gpio4: gpio:, irq:
[ 41.710481] int_demo_isr enter, tiny4412,int_gpio2: gpio:, irq:
[ 41.857190] int_demo_isr enter, tiny4412,int_gpio2: gpio:, irq: [root@tiny4412 mnt]# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
: GIC Edge mct_comp_irq
: GIC Edge MCT
: GIC Edge mmc0
: GIC Edge .hsotg, .hsotg, dwc2_hsotg:usb1
: GIC Edge ehci_hcd:usb2, ohci_hcd:usb3
: GIC Edge .serial
: GIC Edge .i2c
: GIC Edge .pdma
: GIC Edge .pdma
: GIC Edge .mdma
: GIC Edge .pinctrl
: GIC Edge .pinctrl
: COMBINER Edge .pinctrl
: GIC Edge 106e0000.pinctrl
: GIC Edge dw-mci
: exynos4210_wkup_irq_chip Edge mma7660
: exynos_gpio_irq_chip Edge .sdhci cd
: exynos4210_wkup_irq_chip Edge tiny4412,int_gpio1
: exynos4210_wkup_irq_chip Edge tiny4412,int_gpio2
: exynos4210_wkup_irq_chip Edge tiny4412,int_gpio3
: exynos4210_wkup_irq_chip Edge tiny4412,int_gpio4
IPI0: CPU wakeup interrupts
IPI1: Timer broadcast interrupts
IPI2: Rescheduling interrupts
IPI3: Function call interrupts
IPI4: Single function call interrupts
IPI5: CPU stop interrupts
IPI6: IRQ work interrupts
IPI7: completion interrupts
Err:
如果我們修改驅動驅動,改變一下中斷的申請順序,然後重啓系統(測試發現,如果不重啓系統,而是重新加載新的驅動,gpio跟irq的對應關系沒有發生改變)
#if 1
for (i = ; i >= ; i--) {
sprintf(data[i].name, "tiny4412,int_gpio%d", i+);
#else
for (i = ; i < ; i++) {
#endif
此時,會看到如下的log:
[root@tiny4412 mnt]# insmod interrupt_demo.ko
[ 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)
[root@tiny4412 mnt]# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
: GIC Edge mct_comp_irq
: GIC Edge MCT
... ...
: exynos4210_wkup_irq_chip Edge tiny4412,int_gpio4
: exynos4210_wkup_irq_chip Edge tiny4412,int_gpio3
: exynos4210_wkup_irq_chip Edge tiny4412,int_gpio2
: exynos4210_wkup_irq_chip Edge tiny4412,int_gpio1
... ...
未完待續... ...
基於tiny4412的Linux內核移植--- 中斷和GPIO學習(1)的更多相关文章
- 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(3)
作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...
- 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(2)
作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...
- 基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(2)
作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台 tiny4412 ADK Linux-4.9 概述 前面一篇博文基於tiny4412的Linux內核移 ...
- 基於tiny4412的Linux內核移植 --- 实例学习中断背后的知识(1)
作者:彭东林 邮箱:pengdonglin137@163.com QQ:405728433 平台 tiny4412 ADK Linux-4.9 概述 前面几篇博文列举了在有设备树的时候,gpio中断的 ...
- Linux內核中常用的一些延時方法
Linux內核中常用的一些延時方法 這些方法在以下路徑下定義:kernel/include/linux/delay.h #ifndef _LINUX_DELAY_H #define _LINUX_DE ...
- 【转】Linux內核驅動之GPIO子系統(一)GPIO的使用 _蝸牛
原文网址:http://tc.chinawin.net/it/os/article-2512b.html 一 概述 Linux內核中gpio是最簡單,最常用的資源(和interrupt ,dma,ti ...
- 無心插柳的Linux學習者代言人——蔡德明
誰是「蔡德明」恐怕沒有多少人知道,不過提到「鳥哥」這個稱號,在臺灣的Linux社群幾乎是無人不知無人不曉,蔡德明正是鳥哥的本名.鳥哥究竟多有名? 如果你是有意學習Linux的初學者,卻不知如何下手,1 ...
- 第一章 Linux內核簡介
1. Linux是類Unix系統,但他不是Unix. 儘管Linux借鑑了Unix的許多設計並且實現了Unix的API(由Posix標準和其他Single Unix Specification定義的) ...
- 基于tiny4412的Linux内核移植 ---- 調試方法
作者信息 彭東林 郵箱: pengdonglin137@163.com 平臺 Linux-4.4.4 uboot使用的是友善自帶的(爲了支持uImage和設備樹做了稍許修改) 概述 這篇博客主要用於匯 ...
随机推荐
- Elasticsearch 5.0 中term 查询和match 查询的认识
Elasticsearch 5.0 关于term query和match query的认识 一.基本情况 前言:term query和match query牵扯的东西比较多,例如分词器.mapping ...
- 阿里云直播 C# SDK 如何使用
阿里云直播SDK的坑 1.直播云没有单独的SDK,直播部分被封装在CDN的相关SDK当中. 2.针对SDK,没有相关Demo. 3.针对SDK,没有相关的文档说明. 4.针对SDK的说明,官网上的说明 ...
- Hello Web API系列教程——Web API与国际化
软件国际化是在软件设计和文档开发过程中,使得功能和代码设计能处理多种语言和文化习俗,在创建不同语言版本时,不需要重新设计源程序代码的软件工程方法.这在很多成熟的软件开发平台中非常常见.对于.net开发 ...
- ADO.NET对象的详解
1. Connection 类 和数据库交互,必须连接它.连接帮助指明数据库服务器.数据库名字.用户名.密码,和连接数据库所需要的其它参数.Connection对象会被Command对象使用,这样就能 ...
- SASS教程sass超详细教程
SASS安装及使用(sass教程.详细教程) 采用SASS开发CSS,可以提高开发效率. SASS建立在Ruby的基础之上,所以得先安装Ruby. Ruby的安装: 安装 rubyinstaller- ...
- 03.LoT.UI 前后台通用框架分解系列之——多样的表格
LOT.UI分解系列汇总:http://www.cnblogs.com/dunitian/p/4822808.html#lotui LoT.UI开源地址如下:https://github.com/du ...
- Java学习之反射机制及应用场景
前言: 最近公司正在进行业务组件化进程,其中的路由实现用到了Java的反射机制,既然用到了就想着好好学习总结一下,其实无论是之前的EventBus 2.x版本还是Retrofit.早期的View注解框 ...
- 趣说游戏AI开发:曼哈顿街角的A*算法
0x00 前言 请叫我标题党!请叫我标题党!请叫我标题党!因为下面的文字既不发生在美国曼哈顿,也不是一个讲述美国梦的故事.相反,这可能只是一篇没有那么枯燥的关于算法的文章.A星算法,这个在游戏寻路开发 ...
- C#制作简易屏保
前言:前段时间,有个网友问我C#制作屏保的问题,我瞬间懵逼了(C#还可以制作屏保!).于是我去查阅相关资料,下面把C#如何制作屏保的过程及我学习过程的心得也记录下来,希望对需要的人能有帮助. 基本思路 ...
- bash字符串操作
参考 http://www.cnblogs.com/chengmo/archive/2010/10/02/1841355.html 问题:bash怎么提取字符串的最后一位?例如python中strin ...