build_embed_linux_system

驱动设备树接口

设备树一般配合统一驱动模型使用,很多情况下使用总线接口的接口访问(如platform,i2c, spi),不过对于设备树本身也支持访问的接口,在本节将会详细列出。

本节参考地址:https://www.kernel.org/doc/html/v6.1/devicetree/kernel-api.html#

conclusion

dts_node

device_get_child_node_count

//函数原型
int device_get_child_node_count(struct device_node *node)

//参数
node: 设备节点
返回: 设备节点的子节点个数

//例程
int count = device_get_child_node_count(np);

device_for_each_child_node

device_property_read_u32

fwnode_property_read_xx_array

//函数原型
int fwnode_property_read_u8_array(const struct fwnode_handle *fwnode,
                const char *propname, u8 *val,
                size_t nval);
int fwnode_property_read_u16_array(const struct fwnode_handle *fwnode,
                const char *propname, u16 *val,
                size_t nval);
int fwnode_property_read_u32_array(const struct fwnode_handle *fwnode,
                const char *propname, u32 *val,
                size_t nval);
int fwnode_property_read_u64_array(const struct fwnode_handle *fwnode,
                const char *propname, u64 *val,
                size_t nval);
int fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
                const char *propname, const char **val,
                size_t nval);
int fwnode_property_read_string(const struct fwnode_handle *fwnode,
                const char *propname, const char **val);

dts_node_api

of_find_node_by_path

//函数原型
struct device_node *of_find_node_by_path(const char* path)

//参数
path: 在设备树的绝对地址,或者设备节点的别名(alias定义)
返回: 设备树节点结构体

//例程
struct device_node *node0 = of_find_node_by_path("/foo/bar"); //full path
struct device_node *node1 = of_find_node_by_path("foo");      //valid alias
struct device_node *node2 = of_find_node_by_path("foo/bar");  //valid alias + relative path

of_find_node_opts_by_path

//函数原型
struct device_node *of_find_node_opts_by_path(const char* path, const char **opts)

//参数
path: 在设备树的绝对地址,或者设备节点的别名(alias定义)
opts: 用于存储选项字符串开始的指针的地址,该指针以':'分隔符附加到路径的末尾
返回: 设备树节点结构体

//例程
struct device_node *node0 = of_find_node_opts_by_path("/foo/bar", NULL); //full path

of_find_node_by_name

//函数原型
struct device_node *of_find_node_by_name(struct device_node *from, const char *name)

//参数
from: 用于查找起始设备节点,NULL表示从根节点查找整个设备树
name: 用于查找的匹配的设备节点名称
返回: 设备树节点结构体

//例程
led {
    compatible = "rmk,usr-gpio";
};

/* 查找函数 */
struct device_node *led_node;
led_node = of_find_node_by_name(NULL, "led");

of_find_node_by_type

//函数原型
struct device_node *of_find_node_by_type(struct device_node* from, const char* type)

//参数
from: 用于查找的起始设备节点,NULL表示从根节点查找整个设备树
type: 查找节点的device_type属性内容
返回: 设备树节点结构体

//例程
led {
    compatible = "rmk,usr-gpio";
    device_type = "led_type";
};

struct device_node *np;
np = of_find_node_by_type(NULL, "led_type");

of_find_compatible_node

//函数原型
struct device_node *of_find_compatible_node(struct device_node* from, const char *type, const char* compat)

//参数
from: 用于查找的设备节点,NULL表示从根节点查找整个设备树
type: 查找节点的device_type属性内容, NULL表示不检查
compat: 查找匹配的compatible内容
返回: 设备树节点结构体

//例程
led {
    compatible = "rmk,usr-gpio";
    device_type = "led";
};

struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "rmk,usr-gpio");

of_find_matching_node_and_match

//函数原型
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)

//参数
from: 用于查找的设备节点,NULL表示从根节点查找整个设备树
matches: 查找的of_device_id表格
match:匹配的设备树表格
返回: 设备树节点结构体

//例程
static const struct of_device_id versatile_clcd_of_match[] = {
    {
        .compatible = "arm,core-module-integrator",
        .data = (void *)INTEGRATOR_CLCD_CM,
    },
    {
        .compatible = "arm,versatile-sysreg",
        .data = (void *)VERSATILE_CLCD,
    },
};
struct device_node *np;
const struct of_device_id *clcd_id;
np = of_find_matching_node_and_match(NULL, versatile_clcd_of_match, &clcd_id);

of_find_node_by_phandle

//函数原型
typedef u32 phandle;
struct device_node *of_find_node_by_phandle(phandle handle)

//参数
phandle: 节点句柄的结构
返回: 设备树节点结构体

//例程
//读取csi-mux-mipi内容属性
ret = of_property_read_u32_array(np, "csi-mux-mipi", out_val, 3);
if (ret) {
    dev_dbg(csi_dev->dev, "no csi-mux-mipi property found\n");
} else {
    phandle = *out_val;
    node = of_find_node_by_phandle(phandle);
}

of_find_node_with_property

//函数原型
struct device_node *of_find_node_with_property(struct device_node *from,
    const char *prop_name)

//参数
from: 用于查找的设备节点,NULL表示从根节点查找整个设备树
prop_name: 指定节点属性的名称
返回: 设备树节点结构体

//例程
struct device_node *controller = NULL;
controller = of_find_node_with_property(controller, "phys");

of_get_parent

//函数原型
struct device_node *of_get_parent(const struct device_node *node)

//参数
node: 当前定义的设备节点
返回: 当前设备节点的上一级父节点

//例程
struct device_node *firmware_node;
firmware_node = of_get_parent(dev->of_node);

of_get_next_child

//函数原型
struct device_node *of_get_next_child(const struct device_node *node,
    struct device_node *prev)

//参数
node: 当前定义的设备节点
prev: 上一个查询的设备子节点,如果是第一个节点,则为NULL
返回: 函数返回值为查找的子节点,返回NULL表示其节点的子节点不存在

//例程
struct device_node *pcie_intc_node;
pcie_intc_node =  of_get_next_child(node, NULL);

of_node_get

//函数原型
struct device_node *of_node_get(struct device_node *node)

//参数
node: 当前定义的设备节点
返回: 增加计数处理后的节点

//例程
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
if (!cp)
    return -ENOMEM;

cp->node = of_node_get(np);
cp->data = data;
cp->get = clk_src_get;

of_node_put

//函数原型
void of_node_put(struct device_node *node)

//参数
node:已查找的设备树节点

//例程
np = of_node_get(cpu_dev->of_node);
if (!np) {
    dev_err(cpu_dev, "failed to find cpu0 node\n");
    return -ENOENT;
}

of_property_api

of_find_property

//函数原型
struct property *of_find_property(const struct device_node *np, const char *name, int *lenp)

//参数
np: 指向设备的device_node节点的指针
name: 需要获取属性的节点名
lenp: 返回属性内容的对应个数,NULL表示不需要返回
返回: 获取的属性内容结构体

//例程
struct device_node *np = pdev->dev.of_node;
struct property *proper = of_find_property(np, "compatible", NULL);
if(proper == NULL) {
    dbg_err(&pdev->dev, "property find failed\n");
} else {
    dbg_info(&pdev->dev, "compatible = %s\n", (char*)proper->value);
}

of_property_count_elems_of_size

//函数原型
int of_property_count_elems_of_size(const struct device_node *np,
                const char *propname, int elem_size);

//参数
np: 指向设备的device_node节点的指针
propname: 需要统计的元素属性
elem_size: 属性中单个元素的长度
返回: 属性内部元素的个数

//例程
struct device_node *aff
int n;
n = of_property_count_elems_of_size(aff, "cpus", sizeof(u32));
if (WARN_ON(n < 0))
    return;

of_property_read_xx

//函数原型
static inline int of_property_read_u8(const struct device_node *np,
                    const char *propname,
                    u8 *out_value);
static inline int of_property_read_u16(const struct device_node *np,
                    const char *propname,
                    u16 *out_value);
static inline int of_property_read_u32(const struct device_node *np,
                    const char *propname,
                    u32 *out_value);
static inline int of_property_read_s32(const struct device_node *np,
                    const char *propname,
                    s32 *out_value);

//参数
np: 指向设备的device_node节点的指针
propname: 选择的节点属性值
out_value: 返回的节点属性对应数据值
返回: 0表示读取成功,其它表示读取失败

//例程
usr_led {
    compatible = "rmk,usr-led";
    reg = <0x020c406c 0x04>,
        <0x020e0068 0x04>,
        <0x020e02f4 0x04>,
        <0x0209c000 0x04>,
        <0x0209c004 0x04>;
    status = "okay";
};

int ret;
u32 cfg0;
struct device_node *led_node;
led_node = of_find_node_by_path("/usr_led");
ret = of_property_read_u32(led_node, "reg", &cfg0);

of_property_read_xx_index

//函数原型
int of_property_read_u32_index(const struct device_node *np,
                        const char *propname,
                        u32 index, u32 *out_value)
int of_property_read_u64_index(const struct device_node *np,
                        const char *propname,
                        u32 index, u64 *out_value)

//参数
np: 指向设备的device_node节点的指针
propname: 当前选择的属性值
index: 属性内部变量的索引值
out_value: 返回得具体得值,分别代表32位和64位值
返回: 0表示读取成功,其它表示读取失败

//例程
//设备树
gpc: interrupt-controller@20dc000 {
    compatible = "fsl,imx6sll-gpc", "fsl,imx6q-gpc";
    reg = <0x020dc000 0x4000>;
    interrupt-controller;
    #interrupt-cells = <3>;
    interrupts = <0 89 4>;
    interrupt-parent = <&intc>;
    fsl,mf-mix-wakeup-irq = <0x7c00000 0x7d00 0x0 0x1400640>;
};
static u32 gpc_mf_irqs[4];
struct device_node *node;

of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 0,
    &gpc_mf_irqs[0]);
of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 1,
    &gpc_mf_irqs[1]);
of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 2,
    &gpc_mf_irqs[2]);
of_property_read_u32_index(node, "fsl,mf-mix-wakeup-irq", 3,
    &gpc_mf_irqs[3]);

of_property_read_xx_array

//函数原型
int of_property_read_u8_array(const struct device_node *np,
                        const char *propname,
                        u8 *out_values, size_t sz)
int of_property_read_u16_array(const struct device_node *np,
                        const char *propname,
                        u16 *out_values, size_t sz)
int of_property_read_u32_array(const struct device_node *np,
                        const char *propname,
                        u32 *out_values, size_t sz)
int of_property_read_u64_array(const struct device_node *np,
                        const char *propname,
                        u64 *out_values, size_t sz)
                    
//参数
np: 指向设备的device_node节点的指针
propname: 当前选择的属性值
out_values: 读取到得数组值
sz: 读取得数组元素数量
返回: 0表示读取成功,其它表示读取失败

//例程
//设备树
&sata {
    status = "okay";
    /* SATA OOB timing settings */
    ceva,p0-cominit-params = /bits/ 8 <0x18 0x40 0x18 0x28>;
    ceva,p0-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>;
    ceva,p0-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>;
    ceva,p0-retry-params = /bits/ 16 <0x96A4 0x3FFC>;
    ceva,p1-cominit-params = /bits/ 8 <0x18 0x40 0x18 0x28>;
    ceva,p1-comwake-params = /bits/ 8 <0x06 0x14 0x08 0x0E>;
    ceva,p1-burst-params = /bits/ 8 <0x13 0x08 0x4A 0x06>;
    ceva,p1-retry-params = /bits/ 16 <0x96A4 0x3FFC>;
    phy-names = "sata-phy";
    phys = <&psgtr 3 PHY_TYPE_SATA 1 1>;
};

//代码
#define NR_PORTS    2
struct ceva_ahci_priv {
    struct platform_device *ahci_pdev;
    /* Port Phy2Cfg Register */
    u32 pp2c[NR_PORTS];
    u32 pp3c[NR_PORTS];
    u32 pp4c[NR_PORTS];
    u32 pp5c[NR_PORTS];
    /* Axi Cache Control Register */
    u32 axicc;
    bool is_cci_enabled;
    int flags;
    struct reset_control *rst;
};

if (of_property_read_u8_array(np, "ceva,p0-cominit-params",
                (u8 *)&cevapriv->pp2c[0], 4) < 0) {
    dev_warn(dev, "ceva,p0-cominit-params property not defined\n");
    return -EINVAL;
}
if (of_property_read_u8_array(np, "ceva,p1-cominit-params",
                (u8 *)&cevapriv->pp2c[1], 4) < 0) {
    dev_warn(dev, "ceva,p1-cominit-params property not defined\n");
    return -EINVAL;
}
if (of_property_read_u16_array(np, "ceva,p0-retry-params",
                (u16 *)&cevapriv->pp5c[0], 2) < 0) {
    dev_warn(dev, "ceva,p0-retry-params property not defined\n");
    return -EINVAL;
}

of_property_read_string

//函数原型
int of_property_read_string(const struct device_node *np,
        const char *propname,
        const char **out_string);

//参数
np: 指向设备的device_node节点的指针
propname: 需要获取属性的节点名
out_string: 返回节点字符串内容的指针
返回: 获取字符串节点内部值,需要节点为字符串类型

//例程
of_property_read_string(np, "label", &mtd->name);

of_property_read_string_index

//函数原型
static inline int of_property_read_string_index(const struct device_node *np,
        const char *propname,
        int index, const char **output)

//参数
np: 指向设备的device_node节点的指针
propname: 需要获取变量值的节点名
index: 字符串变量的索引值
out_string: 返回节点字符串数组中指定位置标签的字符串指针
返回: 获取字符串节点内部值,需要节点为字符串数组类型

//例程
of_property_read_string_index(parent->of_node, "clock-output-names",
        0, &clk_name);

of_property_read_string_array

//函数原型
static inline int of_property_read_string_array(const struct device_node *np,
    const char *propname, const char **out_strs,
    size_t sz)

//参数
np: 指向设备的device_node节点的指针
propname: 需要获取属性的节点名
out_strs: 读取字符变量的字符串数组首地址
sz: 需要读取的字符串个数
返回: 获取节点属性数组,需要节点为字符串数组类型

//例程
strings[2] = NULL;
of_property_read_string_array(np, "unterminated-string-list", strings, 2);

of_property_match_string

//函数原型
int of_property_match_string(const struct device_node *np, const char *propname,
            const char *string)

//参数
np: 指向设备的device_node节点的指针
propname: 需要获取属性的节点名
out_strs: 读取字符变量的字符串数组首地址
sz: 需要读取的字符串个数
返回: 匹配成功返回位置标签,负值表示失败

//例程
rc = of_property_match_string(np, "phandle-list-names", "first");

of_property_count_strings

//函数原型
static inline int of_property_count_strings(const struct device_node *np,
                    const char *propname)

//参数
np: 指向设备的device_node节点的指针
propname: 需要获取属性的节点名
返回: 返回字符串数组中字符串数目,负值表示失败或者不存在

//例程
count = of_property_count_strings(np, "clock-output-names");

of_property_read_bool

//函数原型
static inline bool of_property_read_bool(const struct device_node *np,
    const char *propname)

//参数
np: 指向设备的device_node节点的指针
propname: 需要获取属性的节点名称
返回: 节点存在返回true,其它表示不存在

//例程
if (!of_property_read_bool(np, "always-on"))
    twd_features |= CLOCK_EVT_FEAT_C3STOP;

of_remove_property

//函数原型
int of_remove_property(struct device_node *np, struct property *prop)

//参数
np: 指向设备的device_node节点的指针
prop: 需要删除的节点
返回: 0表示成功,其它表示失败

//例程
of_remove_property(pcs->np, pcs->missing_nr_pinctrl_cells);

of_add_property

//函数原型
int of_add_property(struct device_node *np, struct property *prop)

//参数
np: 指向设备的device_node节点的指针
prop: 需要增加的节点
返回: 0表示成功,其它表示失败

//例程
error = of_add_property(np, pcs->missing_nr_pinctrl_cells);

of_get_property

//函数原型
const void *of_get_property(const struct device_node *np, const char *name,
            int *lenp)

//参数
np: 指向设备的device_node节点的指针
name: 需要获取属性的节点名
lenp: 返回属性内容的对应个数,NULL表示不需要返回
返回: 获取的属性内容,property->value对象

//例程
const char *enable_method;
enable_method = of_get_property(dn, "enable-method", NULL);

of_update_property

//函数原型
int of_update_property(struct device_node *np, struct property *newprop)

//参数
np: 指向设备的device_node节点的指针
prop: 需要增加的节点
返回: 0表示更新成功,其它表示失败

//例程
struct property *prop;

prop = kzalloc(sizeof(*prop), GFP_KERNEL);
if (!prop)
    return;

prop->name = "compatible";
prop->value = compat;
prop->length = len;

of_update_property(node, prop);

of_n_addr_cells

//函数原型
int of_n_addr_cells(struct device_node *np);

//参数
np: 指向设备的device_node节点的指针
返回: 返回addr_cell属性中的数目

//例程
na = of_n_addr_cells(np);

of_n_size_cells

//函数原型
int of_n_size_cells(struct device_node *np);

//参数
np: 指向设备的device_node节点的指针
返回: 返回size_cells属性中的数目

//例程
na = of_n_size_cells(np);

of_alias_get_id

//函数原型
int of_alias_get_id(struct device_node *np, const char *stem)

//参数
np: 指向设备的device_node节点的指针
stem: 重定义的标签名称
返回: 节点指定的id

//例程
pdev->id = of_alias_get_id(np, "spi");

of_feature_api

of_device_is_compatible

//函数原型
static inline int of_device_is_compatible(const struct device_node *device,
            const char *name)

//参数
device: 匹配的设备节点
name: 检测匹配的设备名称
返回: 0表示匹配检测成功,其它表示失败

//例程
ret = of_device_is_compatible(np, "fsl,imx7ulp-mu-lp");

of_device_compatible_match

//函数原型
int of_device_compatible_match(const struct device_node *device,
            const char *const *compat)

//参数
device: 匹配的设备节点
compat: 检测匹配的设备名称
返回: 0表示匹配失败,其它表示匹配成功

//例程
if (!of_device_compatible_match(dev->of_node, sunxi_mbus_devices))
    return NOTIFY_DONE;

of_device_get_match_data

//函数原型
const void *of_device_get_match_data(const struct device *dev)

//参数
dev: 当前处理的设备
返回:匹配的设备节点内数据

//例程
static const struct of_device_id of_imx_thermal_match[] = {
    { .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, },
    { .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, },
    { .compatible = "fsl,imx7d-tempmon", .data = &thermal_imx7d_data, },
    { /* end */ }
};

struct imx_thermal_data *data;
data->socdata = of_device_get_match_data(&pdev->dev);

of_device_is_available

//函数原型
bool of_device_is_available(const struct device_node *device)

//参数
device: 匹配的设备节点
返回: 节点status="okay""ok"返回true, 其它返回false

//例程
if (!of_device_is_available(np))
    return;

of_get_child_count

//函数原型
static inline int of_get_child_count(const struct device_node *np)

//参数
np: 匹配的设备节点
返回: 设备节点的子节点个数

//例程
hub->num_heads = of_get_child_count(pdev->dev.of_node);

of_get_available_child_count

//函数原型
static inline int of_get_available_child_count(const struct device_node *np)

//参数
np: 匹配的设备节点
返回: 可用子节点个数

//例程
ep_cnt = of_get_available_child_count(port);

of_get_address

//函数原型
static inline const __be32 *of_get_address(struct device_node *dev, int index,
             u64 *size, unsigned int *flags)

//参数
dev: 匹配的设备节点
index: 指定要检索的资源地址的索引。设备树节点中的“reg”属性可能包含多个地址范围,这个参数用于选择其中一个
size: 用于返回存储检索到的资源大小
flags: 用于返回存储与资源相关的标志(如果有的话)。
返回: 资源的地址信息

//例程
const __be32 *addr;
addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL);
dma_reg_base = be32_to_cpup(addr);

of_address_to_resource

//函数原型
int of_address_to_resource(struct device_node *dev, int index, struct resource *r)

//参数
dev: 请求的设备节点
index: 指定要检索的资源地址的索引。设备树节点中的“reg”属性可能包含多个地址范围,这个参数用于选择其中一个
r: 指向资源指针的,存储处理的资源
返回: 0表示获取成功,其它表示失败

//例程
ret = of_address_to_resource(mem_region, 0, &res);
adsp->pa_shared_dram = (phys_addr_t)res.start;      //获取寄存器初始地址
adsp->shared_size = resource_size(&res);            //获取寄存器访问范围

of_iomap

//函数原型
void __iomem *of_iomap(struct device_node *np, int index)

//参数
np: 指向设备的device_node节点的指针
index: I/O mem节点中的索引值
返回: reg节点的io_mem指针

//例程
usr_led {
    //...
    reg = <0x020c406c 0x04>,  //index=0
        <0x020e0068 0x04>,    //index=1
        <0x020e02f4 0x04>,      
        <0x0209c000 0x04>,
        <0x0209c004 0x04>;    //index=3
}
__iomem *io_reg = of_iomap(led_nd, 2);
if (io_reg != NULL) {
    u32 regval = readl(io_reg);
    //...
}

of_clk_get_parent_name

//函数原型
const char *of_clk_get_parent_name(const struct device_node *np, int index)

//参数
np: 指向设备的device_node节点的指针
index: 指定要获取的时钟父节点索引
返回: 时钟父节点的名称,NULL表示失败

//例程
const char *parent_name;
parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name) {
    dev_err(dev, "failed to get clock parent name\n");
    return -ENODEV;
}

of_clk_get_parent_count

of_clk_get_by_name

of_irq_get_byname

of_clk_get

remap

syscon_node_to_regmap

//函数原型
struct regmap *syscon_node_to_regmap(struct device_node *np)

//参数
np: 指向设备的device_node节点的指针
返回: 获取系统的remap指针,后续由remap接口访问

//例程
struct regmap *map;
map = syscon_node_to_regmap(np);

syscon_regmap_lookup_by_compatible

//函数原型
struct regmap *syscon_regmap_lookup_by_compatible(const char *s)

//参数
np: 指向设备的device_node节点的指针
返回: 获取系统的remap指针,后续由remap接口访问

//例程
struct regmap *cfgchip;
cfgchip = syscon_regmap_lookup_by_compatible("ti,da830-cfgchip");

syscon_regmap_lookup_by_phandle

//函数原型
struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
            const char *property)

//参数
np: 指向设备的device_node节点的指针
property: 节点的属性字符串关键字
返回: 获取系统的remap指针,后续由remap接口访问

//例程
struct regmap *map;
map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");

of_hardware

of_get_named_gpio

of_get_named_gpio_flags

of_get_gpio

gpiod_get_from_of_node

gpiod_put

of_gpio_count

of_gpio_named_count

next_chapter

返回目录

直接开始下一节说明: 内核基本资源管理接口