linux设备树-按键中断驱动

发布者:bobojrt最新更新时间:2023-06-05 来源: elecfans关键字:linux  设备树 手机看文章 扫描二维码
随时随地手机看文章

----------------------------------------------------------------------------------------------------------------------------


内核版本:linux 5.2.8

根文件系统:busybox 1.25.0

u-boot:2016.05

----------------------------------------------------------------------------------------------------------------------------


回到顶部

一、修改设备树

1.1 硬件接线

查看Mini2440原理图、S3C2440数据手册,了解如何读取按键的状态。这里粗略介绍一下Mini2440 K1~K6的接线方式:


K1~K6依次对应引脚GPG0、GPG3、GPG5、GPG6、GPG7、GPG11;

按键按下引脚输入低电平、按键松开引脚输入高电平;

1.2 按键读取方式

试想一下,如果我们想判断按键K1有没有按下或者松开,采用中断的方式,按键按下时K1为低电平,松开时为高电平,采用双边沿触发方式;可以极大的提高CPU运行效率。


GPG0、GPG3、GPG5、GPG6、GPG7、GPG11对应的外部中断依次为EINT8、EINT11、EINT13、EINT14、EINT15、EINT19。


1.3 修改s3c2440-smdk2440.dts

在内核arch/arm/boot/dts/s3c2440-smdk2440.dts文件中添加mykey设备节点:


mykey: mykey {

    compatible = "mykey";

    interrupt-parent = <&gpg>;

    interrupts = <0 IRQ_TYPE_EDGE_BOTH>,

                 <3 IRQ_TYPE_EDGE_BOTH>,

                 <5 IRQ_TYPE_EDGE_BOTH>,

                 <6 IRQ_TYPE_EDGE_BOTH>,

                 <7 IRQ_TYPE_EDGE_BOTH>,

                 <11 IRQ_TYPE_EDGE_BOTH>;

    key_1 = <&gpg 0 GPIO_ACTIVE_HIGH>;

    key_2 = <&gpg 3 GPIO_ACTIVE_HIGH>;

    key_3 = <&gpg 5 GPIO_ACTIVE_HIGH>;

    key_4 = <&gpg 6 GPIO_ACTIVE_HIGH>;

    key_5 = <&gpg 7 GPIO_ACTIVE_HIGH>;

    key_6 = <&gpg 11 GPIO_ACTIVE_HIGH>;

};

复制代码

这里指定了中断控制器为gpg,同时指定了每个按键使用的外部中断硬件中断号(需要注意的是这个硬件中断号是从0开始计数的,这主要是因为gpg外部中断控制器有独立的中断域irq_domain),以及中断触发方式。


此外需要引入头文件:


#include      /* 定义了GPIO_ACTIVE_HIGH */

在arch/arm/boot/dts/s3c2440-pinctrl.dtsi文件下有gpg设备节点配置信息:


gpg: gpg {

        gpio-controller;

        #gpio-cells = <2>;

        interrupt-controller;

        #interrupt-cells = <2>;

};

ggio-cells=2:表示使用这个bank的GPIO时,需要用两个32位数去描述;


第1位:表示使用的哪一个引脚;

第2位:表示有效电平;这里全局设置为高电平有效;

回到顶部

二、按键驱动程序

在/work/sambashare/drivers下创建25.button_dev_dts文件夹。用来保存按键驱动程序。


2.1 platform driver定义

这里我们采用platform设备驱动模型,因此需要定义platform_driver:


/*

 * 用于设备树匹配

 */

static const struct of_device_id button_dt_match[] = {

    { .compatible = DTSKEY_NAME, },

    {},

};


/*

 * platform驱动

 */

static struct platform_driver button_driver = {

    .probe = button_probe,

    .remove = button_remove,


    .driver = {

        .name = DTSKEY_NAME,

        .of_match_table = button_dt_match,  // 匹配列表

    }

};


2.2 button_probe


/*

 * 中断处理服务

 */

static irqreturn_t button_irq(int irq, void *dev_id)

{

    printk("%s enter, irq: %d, %sn", __func__, irq, (char *)dev_id);

    return 0;

}


/*

 * 当驱动和硬件信息匹配成功之后,就会调用probe函数,驱动所有的资源的注册和初始化全部放在probe函数中

 */

static int button_probe(struct platform_device *pdev)

{

      int ret = 0, i = 0;

      int num_irq = 0;

      struct device *dev = &pdev->dev;

      char *key_name;


      printk("%s enter.n", __func__);


      if (!dev->of_node) {

            dev_err(dev, "no device tree noden");

            return -EINVAL;

       }


      if(pdev->name != NULL){

            printk("platform device name %s",pdev->name);   // mykey

      }


      for(i = 0; i< IRQ_CNT; i ++){

            // 1. 获取中断资源

            ret = platform_get_irq(pdev, i);

            if (ret <= 0) {

                dev_err(&pdev->dev, "cannot find irq index %dn",i);

                return ret;

            }


            key_name = kasprintf(GFP_KERNEL, "key-%d", i+1);


            // 2. 注册中断服务 中断触发类型设置为0,则使用设备树中的配置

            ret = devm_request_irq(&pdev->dev, ret, button_irq, 0, key_name, key_name);

            if (ret != 0) {

                dev_err(&pdev->dev, "cannot claim irq %dn", ret);

                return ret;

            }

      }

     return 0;

}


这段代码主要就是获取每个按键对应的IRQ编号,然后注册中断服务,在中断服务子程序中,将当前按下的按键名称输出。


2.3 button_remove


/*

 * 硬件信息被移除了,或者驱动被卸载了,全部要释放,释放资源的操作就放在该函数中

 */

static int button_remove(struct platform_device * pdev)

{

    printk("button  driver exitn");

    return 0;

}


2.4 button_drv.c完整代码   

 View Code

2.5 Makefile


KERN_DIR :=/work/sambashare/linux-5.2.8-dt

all:

    make -C $(KERN_DIR) M=`pwd` modules 

clean:

    make -C $(KERN_DIR) M=`pwd` modules clean

    rm -rf modules.order


obj-m += button_drv.o


回到顶部

三、烧录开发板测试

3.1 编译设备树

root@zhengyang:/work/sambashare/linux-5.2.8-dt# make dtbs

  DTC     arch/arm/boot/dts/s3c2416-smdk2416.dtb

  DTC     arch/arm/boot/dts/s3c2440-smdk2440.dtb

编译设备树文件,把前面配置过的arch/arm/boot/dts里的dts文件编译成dtb文件。


将s3c2440-smdk2440.dtb复制到tftp服务器路径下:


root@zhengyang:/work/sambashare/linux-5.2.8-dt# cp /work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts/s3c2440-smdk2440.dtb /work/tftpboot/

3.2 编译驱动

执行make命令编译驱动,并将驱动程序拷贝到nfs文件系统:


root@zhengyang:/work/sambashare/drivers/25.button_dev_dts# cd /work/sambashare/drivers/25.button_dev_dts/

root@zhengyang:/work/sambashare/drivers/25.button_dev_dts# make

root@zhengyang:/work/sambashare/drivers/25.button_dev_dts# cp button_drv.ko /work/nfs_root/rootfs/

3.3 启动内核

uboot启动后,将dtb下载到内存地址0x30001000中:


SMDK2440 # tftp 0x30001000 s3c2440-smdk2440.dtb

然后将内核镜像加载到内存0x30008000地址:


nand read 0x30008000 kernel;

然后可以使用如下命令启动内核:


SMDK2440 # bootm 0x30008000 - 0x30001000   // 无设备树时,直接bootm 0x30008000

//bootm  uImage地址  ramdisk地址  设备树镜像地址

安装驱动:


[root@zy:/]# insmod button_drv.ko

mykey mykey: no pinctrl handle

OF: no dma-ranges found for node(/mykey)

mykey mykey: device is not dma coherent

mykey mykey: device is not behind an iommu

button_probe enter.                                  // 进入button_probe函数

platform device name mykey

OF: of_irq_parse_one: dev=/mykey, index=0            // ① 从interrupts属性中解析到了第1个中断

OF:  parent=/pinctrl@56000000/gpg, intsize=2

OF:  intspec=0

of_irq_parse_raw:  /pinctrl@56000000/gpg:00000000,00000003

OF: of_irq_parse_raw: ipar=/pinctrl@56000000/gpg, size=2

OF:  -> addrsize=1

OF:  -> got it !

OF: of_irq_parse_one: dev=/mykey, index=1            // ② 从interrupts属性中解析到了第2个中断

OF:  parent=/pinctrl@56000000/gpg, intsize=2

OF:  intspec=3

of_irq_parse_raw:  /pinctrl@56000000/gpg:00000003,00000003

OF: of_irq_parse_raw: ipar=/pinctrl@56000000/gpg, size=2

OF:  -> addrsize=1

OF:  -> got it !

OF: of_irq_parse_one: dev=/mykey, index=2           // ③ 从interrupts属性中解析到了第3个中断

OF:  parent=/pinctrl@56000000/gpg, intsize=2

OF:  intspec=5

of_irq_parse_raw:  /pinctrl@56000000/gpg:00000005,00000003

OF: of_irq_parse_raw: ipar=/pinctrl@56000000/gpg, size=2

OF:  -> addrsize=1

OF:  -> got it !

OF: of_irq_parse_one: dev=/mykey, index=3          // ④ 从interrupts属性中解析到了第4个中断 

OF:  parent=/pinctrl@56000000/gpg, intsize=2

OF:  intspec=6

of_irq_parse_raw:  /pinctrl@56000000/gpg:00000006,00000003

OF: of_irq_parse_raw: ipar=/pinctrl@56000000/gpg, size=2

OF:  -> addrsize=1

OF:  -> got it !

OF: of_irq_parse_one: dev=/mykey, index=4         // ⑤ 从interrupts属性中解析到了第5个中断 

OF:  parent=/pinctrl@56000000/gpg, intsize=2

OF:  intspec=7

of_irq_parse_raw:  /pinctrl@56000000/gpg:00000007,00000003

OF: of_irq_parse_raw: ipar=/pinctrl@56000000/gpg, size=2

OF:  -> addrsize=1

OF:  -> got it !

OF: of_irq_parse_one: dev=/mykey, index=5        // ⑥ 从interrupts属性中解析到了第6个中断

OF:  parent=/pinctrl@56000000/gpg, intsize=2

OF:  intspec=11

of_irq_parse_raw:  /pinctrl@56000000/gpg:0000000b,00000003

OF: of_irq_parse_raw: ipar=/pinctrl@56000000/gpg, size=2

OF:  -> addrsize=1

OF:  -> got it !

platform driver registered successfully


这里输出了大量的调试信息,主要是因为我开启了调试日志。


在linux的/sys/firmware/devicetree/base目录下可以查看到 mykey节点,如下图所示:


[root@zy:/]# ls /sys/firmware/devicetree/base/

#address-cells                 mykey

#size-cells                    myled

aliases                        name

chosen                         nand@4e000000

clock-controller@4c000000      pinctrl@56000000

clocks                         rtc@57000000

compatible                     serial@50000000

cpus                           serial@50004000

i2c@54000000                   serial@50008000

interrupt-controller@4a000000  srom-cs4@20000000

[1] [2]
关键字:linux  设备树 引用地址:linux设备树-按键中断驱动

上一篇:Linux设备树学习(一)基本知识点
下一篇:设备树中的中断

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved