驱动篇:ARM Linux 设备树(四)(摘录)

驱动篇:ARM Linux 设备树(四)(摘录)

常用的 OF API
除了前文介绍的 of_machine_is_compatible ()、 of_device_is_compatible ()等常用函数以外,在 Linux 的 BSP 和驱动代码中,经常会使用到一些 Linux 中其他设备树的 API ,这些 API 通常被冠以 of_ 前缀,它们的实现代码位于内核的 drivers/of 目录下。

1 . 寻找节点:

struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compatible);

根据兼容属性,获得设备节点。遍历设备树中的设备节点,看看哪个节点的类型、兼容属性与本函数的输入参
数匹配,在大多数情况下, from 、 type 为 NULL ,则表示遍历了所有节点。

2 . 读取属性

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(const struct device_node *np, const char
*propname, u64 *out_value);

读取设备节点 np 的属性名,为 propname ,属性类型为 8163264 位整型数组。
对于 32 位处理器来讲,最常用的是 of_property_read_u32_array ()

如在 arch/arm/mm/cache-l2x0.c 中,通过如下语句可读取 L2cache 的 “arm , data-latency” 属性:

of_property_read_u32_array(np, "arm,data-latency",
data, ARRAY_SIZE(data));

在 arch/arm/boot/dts/vexpress-v2p-ca9.dts 中,对应的含有 “arm , data-latency” 属性的 L2cache 节点如下:

L2: cache-controller@1e00a000 {
compatible = "arm,pl310-cache";
reg = <0x1e00a000 0x1000>;
interrupts = <0 43 4>;
cache-level = <2>;
arm,data-latency = <1 1 1>;arm,tag-latency = <1 1 1>;
}

在有些情况下,整型属性的长度可能为 1 ,于是内核为了方便调用者,又在上述 API 的基础上封装出了更加简单的读单一整形属性的 API ,它们为 int of_property_read_u8 ()、 of_property_read_u16 ()等,实现于include/linux/of.h 中,如代码清单所示:

static inline int of_property_read_u8(const struct device_node *np,
 const char *propname,u8 *out_value)
{
return of_property_read_u8_array(np, propname, out_value, 1);
}

static inline int of_property_read_u16(const struct device_node *np,
const char *propname,u16 *out_value)
{
return of_property_read_u16_array(np, propname, out_value, 1);
}

static inline int of_property_read_u32(const struct device_node *np,
 const char *propname, u32 *out_value)
{
return of_property_read_u32_array(np, propname, out_value, 1);
}

除了整型属性外,字符串属性也比较常用,其对应的 API 包括:

int of_property_read_string(struct device_node *np, const char *propname,
const char **out_string);
int of_property_read_string_index(struct device_node *np, const char *propname,
int index, const char **output);

前者读取字符串属性,后者读取字符串数组属性中的第 index 个字符串

如 drivers/clk/clk.c 中的of_clk_get_parent_name ()函数就通过 of_property_read_string_index ()遍历 clkspec 节点的所有 “clock-output-names” 字符串数组属性。
在驱动中读取第 index 个字符串的例子:

const char *of_clk_get_parent_name(struct device_node *np, int index)
{
 struct of_phandle_args clkspec;
 const char *clk_name;
 int rc;

if (index < 0)
return NULL;

rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,

&clkspec);
if (rc)
return NULL;

if (of_property_read_string_index(clkspec.np, "clock-output-names",

clkspec.args_count clkspec.args[0] : 0,

&clk_name) < 0)
clk_name = clkspec.np->name;
 of_node_put(clkspec.np);
 return clk_name;
}
EXPORT_SYMBOL_GPL(of_clk_get_parent_name);

除整型、字符串以外的最常用属性类型就是布尔型,其对应的 API为:

static inline bool of_property_read_bool(const struct device_node *np,
const char *propname);

如果设备节点 np 含有 propname 属性,则返回 true ,否则返回 false 。一般用于检查空属性是否存在。

3 . 内存映射

void __iomem *of_iomap(struct device_node *node, int index);

上述 API 可以直接通过设备节点进行设备内存区间的 ioremap (), index 是内存段的索引。若设备节点的 reg 属性有多段,可通过 index 标示要 ioremap ()的是哪一段,在只有 1 段的情况, index 为 0 。采用设备树后,一些设备驱动通过 of_iomap ()而不再通过传统的 ioremap ()进行映射,当然,传统的 ioremap ()的用户也不少。

int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);

上述 API 通过设备节点获取与它对应的内存资源的 resource 结构体。其本质是分析 reg 属性
以获取内存基地址、大小等信息并填充到 struct resource*r 参数指向的结构体中。

4 . 解析中断

unsigned int irq_of_parse_and_map(struct device_node *dev, int index);

通过设备树获得设备的中断号,实际上是从 .dts 中的 interrupts 属性里解析出中断号。
若设备使用了多个中断, index 指定中断的索引号。

5 . 获取与节点对应的 platform_device

struct platform_device *of_find_device_by_node(struct device_node *np);

在可以拿到 device_node 的情况下,如果想反向获取对应的 platform_device ,可使用上述 API 。

当然,在已知 platform_device 的情况下,想获取 device_node 则易如反掌,例如:

static int sirfsoc_dma_probe(struct platform_device *op)
{
struct device_node *dn = op->dev.of_node;
...
}

充斥着 ARM 社区的大量垃圾代码导致 Linus 盛怒,因此该社区在 2011~2012 年进行了大量的修整工作。 ARM Linux开始围绕设备树展开,设备树有自己的独立语法,它的源文件为 .dts ,编译后得到 .dtb , Bootloader 在引导 Linux 内核的时候会将 .dtb 地址告知内核。之后内核会展开设备树并创建和注册相关的设备,因此 arch/arm/mach-xxx 和arch/arm/plat-xxx 中的大量用于注册 platform 、 I 2 C 、 SPI 等板级信息的代码被删除,而驱动也以新的方式与在 .dts中定义的设备节点进行匹配。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值