一、驱动和设备分离
设备树可以统一管理设备,存放所有设备信息。
1、设备树文件类型:
- dts:设备树源文件
- dtsi:设备树头文件
- dtb:编译好的二进制设备树文件,可直接使用
- DTC:编译工具
2、设备树节点语法:
cs
设备名{
#address-cells = <1>;//每个地址所占字节
#size-cells = <1>;//地址大小所占字节
// 寄存器物理地址 + 长度 可以写多组
reg = <地址1 长度1
地址2 长度2
地址3 长度3>;
status = "okey";//设备可用状态
}
3、设备树函数接口:
1).函数:struct device_node *of_find_node_by_path(const char *path);
- 功能:通过路径获得设备树节点
- 参数:@path --- 设备树节点全路径(比如'/myled')
2).函数:int of_property_read_string(struct device_node *np, const char *propname, const char **out_string);
- 功能:读取属性中的字符串值
- 参数:@np --- 设备树节点,@propname --- 要读的属性名,@out_string --- 存放缓冲区
3).函数:void __iomem *of_iomap(struct device_node *np, int index);
- 功能:设备树中的物理地址映射为内核虚拟地址
- 参数:@np --- 设备树节点,@index --- reg数组的下标,从0开始)
二、驱动分层:
设备有4 类寄存器:
- 引脚复用
- 电气属性
- GPIO 方向
- GPIO 数据
将寄存器的配置移入设备树(Device Tree),由 Linux 内核的 pinctrl 子系统 和 GPIO 子系统完成。
1、pinctrl子系统:操作iomuxrc的寄存器
1).pinctrl方案定义
cs
pinctrl_myled:myledgrp{//方案名:组名
fsl,pins = <
//引脚配置宏 电器属性参数
>;
}
2).pinctrl方案使用
cs
设备树节点{
pinctrl-names = "default";//默认按照pinctrl方案定义配置
pinctrl-0 = <&pinctrl方案名>;
};
2、GPIO子系统:操作GPIO的寄存器
cs
设备树节点{
gpio-led = <&gpio控制器编号 gpio引脚号 有效电平>;
};
1).函数:int of_get_named_gpio(struct device_node *np, const char *propname, int index);
- 功能:从设备树节点中解析并获取指定GPIO硬件编号
- 参数:@np --- 设备树节点,@propname --- GPIO子系统名,@index --- 方案编号,从0开始
- 返回值:成功返回引脚编号,失败返回-1
2).函数:int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
- 功能:或得单个GPIO描述符,设备卸载时自动释放
- 参数:@dev --- 设备,@gpio --- 要占用的引脚编号,@label --- 标明占用资源的驱动
3).函数:int gpio_direction_output(unsigned gpio, int value);
- 功能:将GPIO引脚设置为输出模式
- 参数:@gpio --- 引脚编号,@value --- 初始电平
4).函数:int gpio_direction_input(unsigned gpio);
- 功能:将GPIO引脚设置为输入模式
5).函数:int gpio_get_value(unsigned int gpio);
- 功能:读取输入引脚电平
6).函数:void gpio_set_value(unsigned int gpio, int value);
- 功能:设置输出引脚电平
三、Linux中断
Linux 内核有中断子系统,专门管理所有硬件中断,不用我们直接操作寄存器配置中断。中断子系统分为:顶半部 + 底半部。
顶半部:
- 硬件一触发中断立刻执行
- 执行时间必须很短,只做最简单的事:标记中断、读取按键电平
- 不能延时、不能睡眠、不能做耗时操作
底半部:
- 把耗时、复杂的任务挪到底半部执行
- 顶半部快速退出,不占用 CPU,提高系统响应速度
- 常见实现:工作队列、tasklet 等
cs
设备节点{
interrupt-parent = <&gpio1>;//中断控制器
interrupts = <15 IRQ_TYPE_EDGE_FALLING>;//触发方式,例如15下降沿触发
};