# 设备树组成
## 文件类型
```
.dts 是ASCII的文本格式的设备树描述,一个.dts对应一个ARM设备,一般放在arch/arm/boot/dts下
.dtsi 类似c .h文件 是所有公用部分的提炼
dtb 被编译后的文件能够被linux识别 uboot也能识别
dtc是编译 .dts为.dtb的工具
dtc源码在 scripts/dtc/Makefile hostprogs-y:=dtc
ubuntu安装dtc sudo apt-get install device-tree-complier
soc被选中 dtc会被编译
arch/arm/boot/dts/Makefile 列举要编译的设备树
例如:
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-frdm.dtb
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-qds.dtb
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1012a-rdb.dtb
dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls1043a-qds.dtb
```
## 绑定
```
在 Documentation/devicetree/bindings下有绑定有设备绑定信息介绍
```
```
UBoot支持设备树 使能: #define CONFIG_OF_LIBFDT
```
# 根节点兼容
```
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
static const char * const imx6ul_dt_compat[] __initconst = {
"fsl,imx6ul",
"fsl,imx6ull",
"fsl,imx6ulz",
NULL,
};
DT_MACHINE_START(IMX6UL, "Freescale i.MX6 UltraLite (Device Tree)")
.map_io = imx6ul_map_io,
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
.init_late = imx6ul_init_late,
.dt_compat = imx6ul_dt_compat,
MACHINE_END
int of_machine_is_compatible(const char *compat); 判断具体电路板
```
# 设备节点兼容
```
int of_device_is_compatible(const struct device_node *device, const char *); 判断节点属性是否包含
static const struct of_device_id a1234_i2c_of_match[] = {
{.compatible = "acme,a1234-i2c-bus", .data = (void *)&fns}, // .data附加数据
{},
}
MODULE_DEVICE_TABLE(of, a1234_i2c_of_match); 热插拔设备自动加载驱动 usb pcie platform
static struct platform_driver i2c_a1234_driver = {
.driver = {
.name = "a1234-i2c-bus",
.owner = THIS_MODULE,
.of_match_table = a1234_i2c_of_match
}
.probe = i2c_probe
.remove = i2c_remove
}
module_platfrom_driver(i2c_a123_driver) 注册驱动到内核
```
## 一个驱动兼容多个设备
```
1. int of_device_is_compatible(const struct device_node *device, const char *compat)
查看设备兼容属性
2. 设备驱动附加数据 .data
static const struct of_device_id a1234_i2c_of_match[] = {
{.compatible = "acme,a1234-i2c-bus", .data = (void *)&fns}, // .data附加数据
{},
}
```
#
# 设备树常用OF操作函数
## 查找节点的 OF 函数
```
struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
struct device_node *of_find_node_by_type(struct device_node *from, const char *type)
struct device_node *of_find_compatible_node(struct device_node *from,const char *type,const char *compatible)
struct device_node *of_find_matching_node_and_match(struct device_node *from,
const struct of_device_id *matches,
const struct of_device_id **match)
inline struct device_node *of_find_node_by_path(const char *path)
//!
struct device_node *of_get_parent(const struct device_node *node)
struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev)
```
# 设备树使用和语法
## **status属性**
```
值 值 描述
“okay” 表明设备是可操作的。
“disabled”
表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备
插入以后。至于 disabled 的具体含义还要看设备的绑定文档。
“fail”
表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可
操作。
“fail-sss” 含义和“fail”相同,后面的 sss 部分是检测到的错误内容。
```
## **获取匹配入口 of\_device\_id表**
```
const struct of_device_id *of_id =
of_match_device(mxs_auart_dt_ids, &pdev->dev);
if (of_id) {
/* Use of_id->data here */
[...]
}
const struct of_device_id *of_match_device(const struct of_device_id *matches, const struct device *dev);
```
## **获取时钟(clocks )**
```
clocks =
clocks = , ;
clock-names = "nbclk", "fixed";
s->clk = clk_get(&pdev->dev, NULL);
struct clk *clk_get(struct device *dev, const char *id);
clk_prepare(clk);
clk_enable(clk);
clk_disable(clk);
Main kernel clock API
devm_get_clk(): looks up and obtains from the device tree a managed reference to a clock producer, to a root clock or to a clock node.
clk_prepare_enable(): selects a parent clock, configures the corresponding multiplexor and dividor, and enables the clock gating.
clk_disable_unprepare(): unprepares and gate a clock.
clk_get_rate(): obtains the current frequency (in Hz) for a given clock.
clk_set_rate(): sets the frequency for a given clock. If a clock has several parents, the clock framework can change the parent in order to obtain a better frequency.
clk_get_parent(): gets the parent clock source for a given clock
clk_set_parent(): sets the parent clock source for a given clock
foo: foo@abcdefgh {
compatible = "foo-driver";
clocks = , ;
clock-names = "foo1", "foo2";
};
static int foo_probe(struct platform_device *pdev)
{
priv->foo1clk = devm_clk_get(&pdev->dev, "foo1");
if (IS_ERR(priv->foo1clk)) {
ret = PTR_ERR(priv->foo1clk);
if (ret != -ENOENT) {
dev_err(&pdev->dev, "Can't get 'foo1' clock\n");
return ret;
}
}
priv->foo2clk = devm_clk_get(&pdev->dev, "foo2")';
if (IS_ERR(priv->foo2clk)) {
ret = PTR_ERR(priv->foo2clk);
if (ret != -ENOENT) {
dev_err(&pdev->dev, "Can't get 'foo2' clock\n");
return ret;
}
}
}
ret = clk_prepare_enable(priv->foo1clk);
if (ret < 0) {
dev_err(dev, "foo1 clk enable failed\n");
goto err_bclk_disable;
}
```
## **获取IO 寄存器资源(reg)**
```
reg = <0x8006a000 0x2000>
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
port->base = devm_ioremap_resource(&pdev->dev, iores);
struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);
struct resource *platform_get_resource_byname(struct platform_device* *dev*, unsigned int* type*, const char* *name*)
//!映射
void __iomem *devm_platform_ioremap_resource(struct platform_device* pdev, unsigned int *index)
void __iomem *devm_platform_ioremap_resource_byname(struct platform_device* *pdev*, const char* *name*)
```
## **获取中断(interrupts)**
```
interrupts = ,
;
interrupt-parent = ;
interrupts = <18 IRQ_TYPE_EDGE_BOTH>;
int irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
int platform_get_irq(struct platform_device *, unsigned int);
int platform_get_irq_byname(struct platform_device* *dev*, const char* *name*)
//非 platform 获取和映射中断
unsigned int irq_of_parse_and_map(struct device_node *node, int index);
```
*****
## **获取DMA channel (dmas )**
```
dmas = ,
dma-names = "rx", "tx"
s->rx_dma_chan = dma_request_slave_channel(s->dev, "rx");
s->tx_dma_chan = dma_request_slave_channel(s->dev, "tx");
struct dma_chan * __deprecated dma_request_slave_channel(struct device *dev, const char *name);
```
## **pinctrl 子系统**
```
pinctrl_usdhc1: usdhc-1 {
fsl,pins = <
MX6UL_PAD_UART1_RTS_B__GPIO1_IO19 0x17059 /* SD1 CD */
......
>;
};
&usdhc1 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = ;
pinctrl-1 = ;
pinctrl-2 = ;
}
如果 pinctrl-names 为 “default”,那么这种功能状态将设置为默认的引脚状态,代码中无需处理
处理
pctrl = devm_pinctrl_get(dev);
pstate = pinctrl_lookup_state(pctrl, "state_100mhz");
pinctrl_select_state(pctrl, pstate);//设置为输出模式
```
## **gpio子系统**
```
1. 首先设置 pinctrl gpio引脚复用为gpio
pinctrl_led: ledgrp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0x10B0 /* LED0 */
>;
};
2. 定义gpio
gpioled {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-gpioled";
pinctrl-names = "default";
pinctrl-0 = ;
led-gpio = ;
status = "okay";
}
3. 驱动使用
//从设备树获取
int of_gpio_named_count(struct device_node *np, const char *propname)
int of_gpio_count(struct device_node *np)
int of_get_named_gpio(struct device_node *np, const char *propname, int index)
//!设置gpio状态
int gpio_request(unsigned gpio, const char *label)
void gpio_free(unsigned gpio)
int gpio_direction_input(unsigned gpio)
int gpio_direction_output(unsigned gpio, int value)
int gpio_get_value(unsigned gpio)
void gpio_set_value(unsigned gpio, int value)
//获取中断
int gpio_to_irq(unsigned int gpio)
```
#