知识点的(总结篇–知识准备)
一 、pinctrl 和gpio子系统
pinctrl子系统
借助pinctrl子系统来设置一个PIN的复用(用作什么功能和电气属性)
pinctrl_test: testgrp { fsl,pins = < //下面这句话是描述这个pin的设置信息 ,也就是需要设置成什么样子 MX6UL_PAD_GPIO1_IO00__GPIO1_IO00 0x10B0 /*config 是具体设置值*/ >; }MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x0090 0x031C 0x0000 0x5 0x0
< mux_reg conf_reg input_reg mux_mode input_val>
0x0090 0x031C 0x0000 0x5 0x0
IOMUXC父节点首地址0x020e0000 ,因此UART1_RTS_B这个PIN的mux寄存器地址 就是:0x020e0000+0x0090=0x020e 0090 。
conf_reg:0x020e0000+0x031C=0x020e 031C ,这个寄存器就是UART1_RTS_B的电气属性配置寄存器 。
input_reg ,便宜为0 ,表示UART1_RTS_B这个PIN没有input功能 。
mux_mode:5表示复用为GPIO1_IO19 ,将其写入0x020e 0090
input_val:就是写入input_reg寄存器的值 。
GPIO子系统
使用gpio子系统来控制gpio ,控制gpio的输入输出
在设备树中添加设备节点
gpioled { #address-cells = <1>; #size-cells = <1>; compatible = "atkalpha-gpioled"; pinctrl-names = "default"; // pinctrl-0 属性设置 LED 灯所使用的 PIN 对应的 pinctrl 节点 pinctrl-0 = <&pinctrl_led>; 下面这个与gpio子系统有关 //led-gpio 属性指定了 LED 灯所使用的 GPIO ,在这里就是 GPIO1这一组第四个引脚 ,低电平有效(也急速GPIO1d第三个引脚) led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; status = "okay"; };二 、设备树
设备树就是将关于硬件配置信息的文件独立出去 ,驱动程序中只留下关于硬件的操作
修改设备树
1 、添加pinctrl节点
2 、添加设备节点
三 、平台总线框架
主机驱动:一般负责对具体设备进行硬件级别的操作 ,然后向外提交api函数接口 ,主机驱动一般都是开发板厂家写好的
设备驱动:所有的设备驱动都可以调用主机驱动的api函数去实现与外界交互功能
当我们向系统注册一个驱动的时候,总线就会在右侧的设备中查找 ,看看是有没有设备与之匹配的设备 ,如果有的话就将二者联系起来,同样的 ,当向系统中注册一个设备的时候 ,总线就会在左侧的驱动中查找有没有与之匹配的设备
驱动与设备分离
我们知道设备驱动的分离 ,并且引出了总线 、驱动 、设备的模型 ,比如i2c 、spi 、usb等总线 。但是在soc中有些外设没有这个概念 ,但是我们有想使用这个模型 ,Linux提出了platform这虚拟总线 ,于是就对应的platfor_driver和platform_device
当我们向系统注册一个驱动的时候 ,总线就会在右侧的设备中查找 ,看看有没有与之匹配
的设备 ,如果有的话就将两者联系起来 。同样的 ,当向系统中注册一个设备的时候 ,总线就会在左侧的驱动中查找看有没有与之匹配的设备,有的话也联系起来 。Linux 内核中大量的驱动程序都采用总线 、驱动和设备模式 ,我们一会要重点讲解的 platform 驱动就是这一思想下的产物 。1 、platform总线
Linux系统内核用bus_type结构体表示总线
bus_type结构体中 platform_match函数负责驱动与设备的匹配
struct bus_type platform_bus_type = { .name = "platform", .dev_groups = platform_dev_groups, .match = platform_match, .uevent = platform_uevent, .pm = &platform_dev_pm_ops, }2 、platform驱动
struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); struct device_driver driver; //这个结构体变量中包含了设备树匹配的of_match_tableha函数 const struct platform_device_id *id_table; //无设备树匹配 bool prevent_deferred_probe; }第二行: probe 函数 ,当驱动与设备匹配成功以后 probe 函数就会执行,probe函数就是负 责注册驱动设备到内核的哪些东西
第 七 行 driver 成员 ,该结构体中包含了设备树匹配的of_match_table函数
第八行 :id_table 用在与无设备树匹配
注意:在无设备树的时候platform_driver name 和 platfor_device compliate属性 对应就可以匹配上
struct device_driver { const struct of_device_id *of_match_table; //设备树匹配 }驱动入口函数里面调用的platform_driver_register函数向Linux内核注册一个platform驱动
驱动卸载函数里面调用platform_driver_unregister函数卸载platform驱动
编写platform驱动需要的一些东西
0、寄存器地址定义 、因为这里是用地址映射 ,用虚拟地址进行操作 //传统字符设备驱动
1 、设备结构体
2、设备具体操作函数
3 、字符设备驱动操作集(file_operations)
4 、platform驱动的probe函数 ,驱动与设备匹配后此函数就会执行(注册字符设备驱动 ,初始化设备(寄存器地址映射 、设备))
5 、remove()(卸载字符设备驱动 ,取消寄存器地址映射)
6 、匹配列表(如果使用设备树的话通过此匹配表进行驱动匹配)
7 、platform平台驱动结构体(其中包含name(其中name移动要和设备字段相对应) ,匹配列表 ,probe和remove)
8 、驱动模块的加载/卸载
三 、设备树
platform_devices和设备里面具体的节点功能是一样的 ,所以说如果有设备树 ,就没必要整个platform_devices 。在编写基于设备树的platform驱动我们需要注意以下几点:
1.在设备树中创建设备节点
2.编写platform要注意兼容属性
这里需要注意 ,我们就是用
设备节点的compatible属性:“atkalpha-gpioled ”和platform驱动的of_match_table属性表中compatible属性: ”atkalpha-gpioled"来进行匹配的
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!