设备树下的字符设备驱动框架

没有引入设备树时,相关寄存器物理地址是直接定义在驱动文件中的,通过地址映射成为虚拟地址后,再操作虚拟地址完成GPIO的初始化。设备树的本质也是操作寄存器,只不过寄存器的相关信息放在了设备树中,配置寄存器时使用OF函数从设备树中读取寄存器数据后再进行配置

下图为设备树下的字符设备驱动框架图:

接下来根据上面的框架图,以驱动LED (GPIO1_IO03)为例,分步介绍具体的代码编写流程

1. 修改设备树文件

在内核源码的/arch/arm/boot/dts/文件夹中复制一份官方I.MX6ULL EVK EMMC版的设备树文件imx6ull-14x14-evk-emmc.dts,并自定义文件名,此处重命名为了imx6ull-andyxi-emmc.dts,在根节点中添加LED设备节点

andyxiled {#address-cells = <1>;      /*reg中起始地址占用一个字长*/#size-cells = <1>;         /*reg中地址长度占用一个字长*/compatible = "andyxi-led";status = "okay";reg = < 0X020C406C 0x04    /*CCM_CCGR1_BASE*/ 0X020E0068 0x04    /*SW_MUX_GPIO1_IO03_BASE*/0X020E02F4 0x04    /*SW_PAD_GPIO1_IO03_BASE*/0X0209C000 0x04    /*GPIO1_DR_BASE*/0X0209C004 0x04 >; /*GPIO1_GDIR_BASE*/
};

设备树修改完成后,在内核源码的根目录下执行make命令编译设备树

make dtbs                       #编译设备树
make imx6ull-andyxi-emmc.dtb    #单独编译指定设备树

编译完成后,使用新的设备树启动Linux内核,之后可进入/proc/device-tree文件夹查看dtsled节点是否存在

#启动Linux系统后,在开发板中查看节点
cd /proc/device-tree         #查看andyxiled节点是否存在

2. 编写驱动程序

创建驱动程序文件dtsled.c,添加如下代码

⏩ 宏定义及设备结构体定义

#define DTSLED_CNT 1            //设备号个数
#define DTSLED_NAME "dtsled"    //名字
#define LEDOFF 0                //关灯
#define LEDON 1                 //开灯
/* 映射后的寄存器虚拟地址指针 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;
/* dtsled 设备结构体 */
struct dtsled_dev{dev_t devid;               //设备号struct cdev cdev;          //cdevstruct class *class;       //类struct device *device;     //设备int major;                 //主设备号int minor;                 //次设备号struct device_node *nd;    //设备节点
};struct dtsled_dev dtsled;      //led设备

⏩ 编写设备操作函数:设备操作函数和LED开关函数,具体代码可参考Linux点灯一文相关部分

⏩ 驱动入口函数中:使用OF函数获取设备树中的属性值,并初始化

static int __init led_init(void) { u32 val = 0; int ret; u32 regdata[14]; const char *str; struct property *proper; /* 获取设备树中的属性数据 */ /* 1、获取设备节点:andyxiled */ dtsled.nd = of_find_node_by_path("/andyxiled"); if(dtsled.nd == NULL) { printk("andyxiled node can not found!\r\n"); return -EINVAL; } else { printk("andyxiled node has been found!\r\n"); } /* 2、获取compatible属性内容 */ proper = of_find_property(dtsled.nd, "compatible", NULL); if(proper == NULL) { printk("compatible property find failed\r\n"); } else { printk("compatible = %s\r\n", (char*)proper->value); }  /* 3、获取status属性内容 */ ret = of_property_read_string(dtsled.nd, "status", &str); if(ret < 0){ printk("status read failed!\r\n"); } else { printk("status = %s\r\n",str); }/* 4、获取reg属性内容 */ ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10); if(ret < 0) { printk("reg property read failed!\r\n"); } else { u8 i = 0; printk("reg data:\r\n"); for(i = 0; i < 10; i++) printk("%#X ", regdata[i]); printk("\r\n"); }/* 初始化LED */
#if 0 /* 1、寄存器地址映射 */ IMX6U_CCM_CCGR1 = ioremap(regdata[0], regdata[1]); SW_MUX_GPIO1_IO03 = ioremap(regdata[2], regdata[3]); SW_PAD_GPIO1_IO03 = ioremap(regdata[4], regdata[5]); GPIO1_DR = ioremap(regdata[6], regdata[7]); GPIO1_GDIR = ioremap(regdata[8], regdata[9]);
#else IMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0); SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1); SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2); GPIO1_DR = of_iomap(dtsled.nd, 3); GPIO1_GDIR = of_iomap(dtsled.nd, 4);
#endif /* 2、使能GPIO1时钟 */ val = readl(IMX6U_CCM_CCGR1); val &= ~(3 << 26);     //之前的设置val |= (3 << 26);      //设置新值writel(val, IMX6U_CCM_CCGR1); /* 3、设置GPIO1_IO03复用功能,并设置IO属性 */ writel(5, SW_MUX_GPIO1_IO03); writel(0x10B0, SW_PAD_GPIO1_IO03); /* 4、设置GPIO1_IO03为输出功能 */ val = readl(GPIO1_GDIR); val &= ~(1 << 3);      //之前的设置 val |= (1 << 3);       //设置为输出writel(val, GPIO1_GDIR); /* 5、默认关闭LED */ val = readl(GPIO1_DR); val |= (1 << 3); writel(val, GPIO1_DR);

⏩ 驱动入口函数中:注册字符设备驱动,代码与Linux点灯一文中的一样

⏩ 驱动出口函数中:注销设备驱动,删除类和设备,代码可参考Linux点灯一文

3. 编写测序程序

实现操作驱动文件对外设进行控制的功能。创建测试程序文件dtsledApp.c,代码内容与Linux点灯一文中的测试程序代码一致,此处不再赘述

4. 编译测试

⏩ 编译驱动程序:当前目录下创建Makefile文件,并make编译

KERNELDIR := /home/andyxi/linux/kernel/linux-imx-rel_imx_4.1.15_2.1.0_ga_andyxi
CURRENT_PATH := $(shell pwd)
obj-m := dtsled.obuild: kernel_moduleskernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

⏩ 编译测试程序:无需内核参与,直接编译即可

arm-linux-gnueabihf-gcc dtsledApp.c -o dtsledApp

⏩ 运行测试:拷贝驱动模块和测试程序到开发板,启动开发板,加载驱动模块后,使用应用程序测试驱动是否正常工作

depmod                         #第一次加载驱动的时候需运行此命令
modprobe dtsled.ko             #加载驱动
./dtsledApp /dev/dtsled 1      #打开LED灯
./dtsledApp /dev/dtsled 0      #关闭LED灯
rmmod dtsled.ko                #卸载驱动模块

设备树下的字符设备驱动框架相关推荐

  1. I.MX6ULL ARM驱动开发---设备树下的platfrom设备驱动

    引言   最新的 Linux 内核已经支持了设备树,因此在设备树下如何编写 platform 驱动就显得尤为重要,本章我们就来学习一下如何在设备树下编写 platform 驱动. 一.设备树下的 pl ...

  2. 设备树下的platform 驱动编写

    目录 设备树下的platform 驱动简介 硬件原理图分析 实验程序编写 修改设备树文件 platform 驱动程序编写 编写测试APP 运行测试 编译驱动程序和测试APP 运行测试 上一章我们详细的 ...

  3. 【正点原子MP157连载】第三十五章 设备树下的platform驱动编写-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  4. Linux 有/无设备树下 platform_driver 驱动框架

    文章目录 platform 驱动框架 platform 设备框架 有设备树下驱动开发注意事项 宏___一行代码创建 platform_driver platform 驱动框架 首先,定义一个 plat ...

  5. 设备树下字符设备驱动

    设备树下字符设备驱动 一.在设备树里添加自己的节点 二.驱动代码 三.makefile 四.应用层代码 运行测试 总结 一.在设备树里添加自己的节点 alphaled { 2 #address-cel ...

  6. 设备树下的 platform 驱动开发框架

    1. 设备树下的platform驱动开发 platform驱动框架分为总线.设备和驱动,其中总线是由Linux内核提供,在编写驱动时只要关注于设备和驱动的具体实现即可.Linux下的platform驱 ...

  7. Linux 设备树下的 platform 驱动实验基于正点原子IMX6ULL开发板

    1 设备树下的 platform 驱动简介 platform 驱动框架分为总线.设备和驱动,其中总线不需要我们这些驱动程序员去管理,这个是 Linux 内核提供的,我们在编写驱动的时候只要关注于设备和 ...

  8. Linux 设备树下的 platform 驱动示例

    1.简介 基于总线.设备和驱动这样的驱动框架,Linux 内核提出来 platform 这个虚拟总线,相应的也有 platform 设备和 platform 驱动. Linux 总线设备和驱动模式 2 ...

  9. 设备树下的platform驱动编写

    文章目录 一.设备树下的platform驱动简介 1.在设备树中创建设备节点 2.编写 platform 驱动的时候要注意兼容属性 3.编写platform驱动 二.硬件原理图分析 三.实验程序编写 ...

最新文章

  1. 展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告...
  2. 成功解决ImportError: Missing optional dependency ‘fastparquet‘. fastparquet is required for parquet supp
  3. Python:matplotlib绘图
  4. 汉三水属国(北地属国、安定属国)
  5. poj 1060 Modular multiplication of polynomials
  6. Telnet远程访问思科交换机、路由器
  7. Android input keyevent
  8. python tab和空格混用_Python编程常见十大错误,看完你自己都笑了!
  9. mysql fixed数据类型_fixed数据类型
  10. 电子信息系统机房设计规范
  11. 群控源码源代码,微群控系统源码的实现原理,核心源码实现 核心框架,可二次开发
  12. npy/npz/pkl/csv长字符串存储
  13. python练习题003:圆的面积
  14. 2022-03微软漏洞通告
  15. linux csv乱码,CSV格式文件中文乱码问题解决
  16. 闪付卡(QuickPass)隐私泄露原理
  17. vc6.0是c语言吗,vc6.0我二级报的是C语言,听说现在C语 – 手机爱问
  18. 物资学院、草房、常营点过的外卖总结
  19. 算法梳理(二)逻辑回归算法梳理
  20. hightcharts-vue 蜡烛图 股票绘图 candlestick

热门文章

  1. 中山大学学报(自然科学版)Latex模板(非官方)
  2. 如何对项目的研发团队年终绩效考核?
  3. 【电影】英国男演员杠把子
  4. Fabric-samples开发模式下chaincode操作流程及错误锦集
  5. RAR Extractor - The Unarchiver Pro for mac(解压缩软件)v6.3.5激活版
  6. VPP使用介绍(route、tun、memif、abf)
  7. php 判断号码运营商,PHP根据手机号判断运营商(详细介绍附代码)
  8. openssl:Can‘t load /home/test/.rnd into RNG
  9. Python中关于浮点数运算的不确定尾数的解释
  10. 解决MAC下MySQL忘记初始密码的方法