----------------------------------------------------------------------------------------------------------------------------
内核版本: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 在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
上一篇:Linux设备树学习(一)基本知识点
下一篇:设备树中的中断
设计资源 培训 开发板 精华推荐
- 12V 交流转直流单输出笔记本电源
- 具有平均模式电流控制的 HV9967B 集成 LED 驱动器的典型应用
- LTC3406ES5-1.5 单节锂离子 1.2V/600mA 稳压器的典型应用电路,用于实现高效率和小尺寸
- 【课程设计】PasswordBook随身携带密码本
- 基于C8051F413 8051 MCU的录音机电路
- LT3091HFE 低压降工作在非常低的输出电压下的典型应用
- MAXREFDES150#Pocket IO PLC开发平台
- LTC4225-1 演示板、双路理想二极管 / 双路热插拔控制器,故障后具有闩锁功能
- LTC3822,大电流应用在 15A 时提供 1.8V
- 用于手机的 4-LED 白光 LED 驱动器