全志_基於dts設備樹驅動開發

基於設備樹開發


平臺:A64
源碼:Linux3.10

路徑:Linux/arch/arm(arm64)/boot/dts/    ***.dts    Makefile    //A64 是64位,選擇arm64


Linux2.6 以前沒有dts(arch/arm/plat-xxx和arch/arm/mach-xxx存在大量垃圾代碼)

dts:結點+屬性(name=value)
dts---(dtc)--->dtb


DT
DTS
DTSI
OF:open firmware 開源硬件
FDT
DTB
DTC

語法:
1.根節點    /{
2.節點-子節點    <名稱>[@<設備地址>]    cpu@1 []可省,每一個節點都須要一個compatible屬性
3.屬性
compatible屬性    做用:匹配    compatible = "jk,leds";
#address-cells和#size-cells屬性    做用:地址佔cell個數和長度佔cell個數    #address-cells = <2> #size-cells = <1> 描述子節點
reg屬性    做用:地址    reg = <address1 length1 [address2 length2][address3 length3]>
中斷信息屬性--interrupts    中斷號
#interrupt-cells    中斷控制器字節屬性

添加節點:
node@12345{
compatible = "jk,leds";
reg = <0x1111 0x111>



1.內核啓動會加載dtb文件,加載信息到系統
2.節點位置:ls proc/device-tree    (設備樹節點信息)

 

 


static int__init dt_drv_init(void)
{
/*
在代碼中獲取整個節點信息



*/
//1.先獲取節點
of_find_node_by_path("/text@123");

//2.獲取節點中屬性
of_find_property();



return 0;
}


static void__exit dt_drv_init(void)
{


}

 

 

module_init(dt_drv_init);
module_exit(de_drv_exit);
modules_license("GPL");

 


#gpio-cells = <6>」表示在設備樹裏描述使用一個gpio口須要提供6個指定的參數.

gpio = <&pio 1 1 1 1 1 0>;
| | | | | | | |-------------------表示有效電平
| | | | | | |----------------------上下拉, 0關閉功能, 1上拉, 2下拉, 3保留
| | | | | |--------------------------驅動力,電流等級(0 - 3),級別越高,輸出電流越大
| | | | |------------------------------gpio功能類型(複用類型),0輸入, 1輸出, 6和外部中斷,7關閉功能(具體查手冊)
| | | |----------------------------------pin bank 內偏移(即組內第幾個io口).
| | |--------------------------------------哪組gpio, PA(0),PB(1),PC(2),PD(3),PE(4),PF(5),PG(6),PH(7),PI(8),PJ(9),PK(10),PL(11)
| |-------------------------------------------指向哪一個gpio控制器, pio / r_pio(PL組)
|--------------------------------------------------屬性名字(隨便命名)


1.兩個GPIO控制器    r_pio pio

___________________________________________________________________________________

獲取設備樹裏設備節點的gpio口信息:

#include <linux/of_gpio.h>

//只需一個函數便可
int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags);

/*
功能:函數用於獲取指定名稱的 gpio 信息
np: 須要查找 GPIO 的節點;
propname: GPIO 信息的屬性名字;
index:    屬性 propname 中屬性值的索引(表示獲取屬性裏的第幾個值);    
flags: 存放 gpio 的 flags;
返回值: 成功:返回 gpio 編號, flags 存放 gpio 配置信息;失敗:返回 null
*/

 


//其中flags必定得注意,按文檔裏的說明應就是一個int類型的值,但根本就不能爲int參數(會致使kernel panic),
//經過閱讀內核裏的代碼得出, flags的參數應爲struct gpio_config類型. 定義在下面文件:

"include/linux/sys_config.h"
struct gpio_config {
u32 gpio; /* gpio global index, must be unique */
u32 mul_sel; /* multi sel val: 0 - input, 1 - output... */
u32 pull; /* pull val: 0 - pull up/down disable, 1 - pull up... */
u32 drv_level; /* driver level val: 0 - level 0, 1 - level 1... */
u32 data; /* data val: 0 - low, 1 - high, only vaild when mul_sel is input/output */
};


/* 節點 */
struct device_node {
const char *name; /* 節點中屬性爲name的值 */
const char *type; /* 節點中屬性爲device_type的值 */
char    *full_name; /* 節點的名字,在device_node結構體後面放一個字符串,full_name指向它 */
struct    property *properties; /* 鏈表,鏈接該節點的全部屬性 */
struct    device_node *parent; /* 指向父節點 */
struct    device_node *child; /* 指向孩子節點 */
struct    device_node *sibling; /* 指向兄弟節點 */
};

/* 屬性 */
struct property {
char    *name; /* 屬性的名字,指向設備樹文件的string block */
int    length; /* 屬性名字的字節數 */
void    *value; /* 屬性的值,指向struct block */
struct property *next; /* 鏈表,鏈接下一個屬性 */
};

 

Linux 系統爲 device tree 提供了標準的 API 接口:
(OF:    API)

1.    unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
/*
功能:函數用於獲取中斷號
dev: 要解析中斷號的設備;
index: dts 源文件中節點 interrupt 屬性值索引
返回值:解析成功返回中斷號,失敗:返回 0
*/

2.    void __iomem *of_iomap(struct device_node *np, int index);
/*
功能:函數用於獲取映射內存
np: 映射內存的設備節點;
index: dts 源文件中節點 interrupt 屬性值索引;
返回值:映射成功 IO memory 的虛擬地址,失敗:返回 NULL
*/


3.    static inline int of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value)
/*
功能:函數用於獲取節點中的屬性值
np: 獲取屬性值的節點
propname: 屬性名稱;
out_value:屬性值
返回值: 映射成功 IO memory 的虛擬地址,失敗:返回 NULL
*/


4.    static inline int of_property_read_string_index(struct device_node *np, const char *propname, const char **output)
/*
功能:函數用於獲取節點中屬性值
np: 獲取屬性值的節點
propname: 屬性名稱;
output: 存放返回字符串;
返回值: 取值成功,返回 0
*/


5.    static inline int of_property_read_string_index(struct device_node *np, const char *propname, int index, const char **output)
/*
功能:函數用於獲取節點中屬性值
np: 獲取屬性值的節點
propname: 屬性名稱;
index: 索引配置在 dts 中屬性爲 propname 的值;
output:    存放返回字符串
返回值: 取值成功,返回 0
*/


6.    extern struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
/*
功能:函數用於獲取指定名稱的節點
from: 開始查找節點,若是爲NULL,則從根節點開始;
name: 節點名字;
返回值: 成功:獲得節點的結構體首地址;失敗:NUL
*/


7.    extern struct device_node *of_find_node_by_name(struct device_node *from, const char *type);
/*
功能:函數用於獲取指定 device_type 的節點
from: 開始查找節點,若是爲NULL,則從根節點開始;
type: 節點名字;
返回值: 成功:獲得節點的結構體首地址;失敗:NUL
*/


8.    extern struct device_node *of_find_node_by_path(const char *path);
/*
功能:函數用於獲取指定路徑的節點
path: 經過指定路徑查找節點;
返回值: 成功:獲得節點的結構體首地址;失敗:NUL
*/


9.    int of_get_named_gpio_flags(struct device_node *np, const char *propname, int index, enum of_gpio_flags *flags)
/*
功能:函數用於獲取指定名稱的 gpio 信息
np: 須要查找 GPIO 的節點;
propname: GPIO 信息的屬性;
index:    屬性 propname 中屬性值的索引;    
flags: 存放 gpio 的 flags;
返回值: 成功:返回 gpio 編號, flags 存放 gpio 配置信息;失敗:返回 null
*/

 

___________________________________________________________________________________


獲取到int類型的gpio口後,就能夠使用linux/gpio.h裏的gpio口操做函數:

#include <linux/gpio.h> //裏面聲明io口的操做函數

int gpio_request(unsigned gpio, const char *label); //每一個io只能被請求一次,可防止多個驅動來控制同一個IO口
void gpio_free(unsigned gpio);    //釋放已請求的io口
int gpio_direction_input(unsigned gpio); //做輸入功能, gpio用於指定具體哪一個io口
int gpio_direction_output(unsigned gpio, int value); //做輸出功能,並根據value的值輸出高低電平
int gpio_get_value(unsigned gpio); //獲取指定IO口的電平
void gpio_set_value(unsigned gpio, int value); //設置IO口的電平爲value(0/1)
int gpio_to_irq(unsigned gpio); //根據io口,獲取到它對應的中斷號(io口大都有外部中斷功能)
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)


___________________________________________________________________________________

設備樹裏的描述:

jkbuzzer {
compatible = "jk,buzzer";
gpios = <&pio 3 24 1 1 1 1>; 
};

jkleds {
compatible = "jk,leds";
gpios = <&r_pio 11 10 1 1 1 1>, <&r_pio 11 12 1 1 1 1>;
};


//PH8
text {
compatible = "text_";
gpios = <&pio 7 9 1 1 1 0>;
};

 


___________________________________________________________________________________

代碼測試:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/sys_config.h>
#include <linux/delay.h>

int myprobe(struct platform_device *pdev)
{
struct device_node *nd = pdev->dev.of_node;
int gpio; 
struct gpio_config config;


printk("gpio count:%d\n", of_gpio_named_count(nd, "gpios"));
gpio = of_get_named_gpio_flags(nd, "gpios", 0, (enum of_gpio_flags *)&config);
if (!gpio_is_valid(gpio))
printk("gpio isn't valid\n");
if (gpio_request(gpio, pdev->name) < 0)
printk("gpio request failed %d\n", gpio);

gpio_direction_output(gpio, 1);
msleep(3000);
gpio_direction_input(gpio);
gpio_free(gpio);
return 0;
}

int myremove(struct platform_device *pdev)
{
printk("in myremove ...\n");
return 0;
}

struct of_device_id ids[] = {
{.compatible = "jk,buzzer"},
{},
};

struct platform_driver mydrv = {
.probe = myprobe,
.remove = myremove,

.driver = {
.owner = THIS_MODULE,
.name = "mydrv" ,

.of_match_table = ids,
},
};

module_platform_driver(mydrv);
MODULE_LICENSE("GPL");

 

 

代碼測試:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/sys_config.h>
#include <linux/delay.h>

int myprobe(struct platform_device *pdev)
{
struct device_node *nd = pdev->dev.of_node;
int gpio, n, i; 
struct gpio_config config;


n = of_gpio_named_count(nd, "gpios");
for (i = 0; i < n ; i++)
{
gpio = of_get_named_gpio_flags(nd, "gpios", i, (enum of_gpio_flags *)&config);
if (!gpio_is_valid(gpio))
printk("gpio isn't valid\n");
if (gpio_request(gpio, pdev->name) < 0)
printk("gpio request failed %d\n", gpio);

gpio_direction_output(gpio, 1);
msleep(3000);
gpio_direction_input(gpio);
gpio_free(gpio);
}
return 0;
}

int myremove(struct platform_device *pdev)
{
printk("in myremove ...\n");
return 0;
}

struct of_device_id ids[] = {
{.compatible = "jk,leds"},
{},
};

struct platform_driver mydrv = {
.probe = myprobe,
.remove = myremove,

.driver = {
.owner = THIS_MODULE,
.name = "mydrv" ,

.of_match_table = ids,
},
};

module_platform_driver(mydrv);
MODULE_LICENSE("GPL");

 

 

 

 

 

 

 

優質博客:
https://blog.csdn.net/jklinux/article/details/82391923
http://www.pianshen.com/article/520912458/
https://www.linuxidc.com/Linux/2017-02/140818.htm

 
相關文章
相關標籤/搜索