了解设备树API(2)
1 常用的OF API作用函数返回值类型参数作用寻找节点struct device_node *of_find_compatible_node();struct device_node *struct device_node *from, const char *type, const char *compatible根据兼容属性,获取设备节点;在大多数情况下,from,type 为NULL, 则
·
1 内核中的设备树API
作用 | 函数 |
---|---|
遍历节点下的所有子节点 | for_each_child_of_node(dev) |
判断具体的设备匹配 | int of_device_is_compatible(const struct device_node* device, const char *compat) |
展开platform_device | of_platform_bus_probe(NULL, xxx_of_bus_ids, NULL) |
找到匹配节点,返回数据 | of_find_matching_node(NULL, 12x0_ids); 例子 |
匹配节点 | of_match_node(12x0_ids, np); 例子 |
不关心名字,获取gpio | of_get_gpio(struct device_node *np, int index) |
关心gpio名字的情况 | of_get_named_gpio(np, “cd-gpios”, 0); 例子 |
获取platform中断 | int platform_get_irq(struct platform_device *dev, unsigned int num) |
被命名了的platform中断获取 | platform_get_irq_byname(pdev, “dema-tx”); 例子 |
获取时钟 | devm_clk_get(&pdev->dev, “general”); 例子 |
2 常用的OF API
序号 | 作用 | 函数 | 参数 | 作用 |
---|---|---|---|---|
1 | 寻找节点 | struct device_node * of_find_compatible_node(); | 1)struct device_node *from, 2)const char *type, 3)const char *compatible | 根据兼容属性,获取设备节点; 在大多数情况下,from,type 为NULL, 则表示遍历了所有节点。 |
2 | 读取属性 | int of_property_read_u8/16/32/u64_array(); | 1)const struct device_node *np, 2)const char *propname, 3)u8/16/32/64 *out_values, 4)size_t sz | 读取设备节点np的属性名,常用的是u32 |
3 | 字符串属性 | int of_property_read_string(); | 1)struct device_node *np, 2)const char *propname, 3)const char **out_string. | 读取字符串 |
3-1 | - | int of_property_read_string_index(); | 1)struct device_node *np, 2)const char *propname, 3)int index, 4)const char**output | 读取字符串数组属性中的第index个字符串 |
4 | 读取bool型属性 | static inline bool of_property_read_bool(); | 1)const struct device_node *np, 2)const char *propname | 如果设备节点np有propname属性,返回true,否则返回false. 一般用于检查空属性是否存在 |
5 | 内存映射 | void __iomem * of_iomap(); | 1)struct device_node *node, 2) int index | 可以通过设备节点进行设备内存区间的ioremap(),index是内存段的索引。 若设备节点的reg属性有多段,可以通过index标示要ioremap()的是哪一段。 只有1段的情况下,index为0。 |
6 | 通过设备节点获取与它对应的内存资源的resource结构体 | int of_address_to_resource(); | 1)struct device_node *dev, 2)int index, 3)struct resource *r | 本质是分析reg属性以获取内存基地址、大小等信息并填充到struct resource *r参数指向的结构体中。 |
7 | 解析中断 | unsigned int irq_of_parse_and_map(); | 1)struct device_node *dev, 2)int index | 通过设备树获取设备的中断号, 实际上是从.dts中的interrupts属性里解析出中断号。 若设备使用了多个中断,index指定中断的索引号。 |
8 | 获取与节点对应的platform_device | struct platform_device * of_find_device_by_node(); | 1)struct device_node *np | 在可以拿到device_node的情况下,如果想反向获取对应的platform_device,可使用该API; 反之,则可以使用: **device_node *dn = op->dev.of_node;**获取。注:op 为 platform_device *op 类型。 |
9 | 根据路径找到节点 | struct device_node * of_find_node_by_path(); | 1)struct device_node *from, 2)const char *path | from:开始查找的节点,NULL表示从根节点开始查找; path:查找的节点名 |
10 | 根据“device_type“属性来查找节点 | struct device_node * of_find_node_by_type(); | 1)struct device_node *from, 2)const char *type | 不建议使用, 建议使用1 |
11 | 节点属性名 | struct property * of_find_property(); | 1)const struct device_node *np, 2)const char *name, 3)int *lenp | 查找节点中的属性 |
试读一个设备树相关的代码
#linux-4.9.88\drivers\gpio\gpio_ath79.c
static int ath79_gpio_probe(struct platform_device *pdev)
{
struct ath79_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct ath79_gpio_ctrl *ctrl;
struct resource *res;
u32 ath79_gpio_count;
bool oe_inverted;
int err;
ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return -ENOMEM;
platform_set_drvdata(pdev, ctrl);
if (np) {
err = of_property_read_u32(np, "ngpios", &ath79_gpio_count);
if (err) {
dev_err(&pdev->dev, "ngpios property is not valid\n");
return err;
}
oe_inverted = of_device_is_compatible(np, "qca,ar9340-gpio");
} else if (pdata) {
ath79_gpio_count = pdata->ngpios;
oe_inverted = pdata->oe_inverted;
} else {
dev_err(&pdev->dev, "No DT node or platform data found\n");
return -EINVAL;
}
if (ath79_gpio_count >= 32) {
dev_err(&pdev->dev, "ngpios must be less than 32\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ctrl->base = devm_ioremap_nocache(
&pdev->dev, res->start, resource_size(res));
if (!ctrl->base)
return -ENOMEM;
spin_lock_init(&ctrl->lock);
err = bgpio_init(&ctrl->gc, &pdev->dev, 4,
ctrl->base + AR71XX_GPIO_REG_IN,
ctrl->base + AR71XX_GPIO_REG_SET,
ctrl->base + AR71XX_GPIO_REG_CLEAR,
oe_inverted ? NULL : ctrl->base + AR71XX_GPIO_REG_OE,
oe_inverted ? ctrl->base + AR71XX_GPIO_REG_OE : NULL,
0);
if (err) {
dev_err(&pdev->dev, "bgpio_init failed\n");
return err;
}
/* Use base 0 to stay compatible with legacy platforms */
ctrl->gc.base = 0;
err = gpiochip_add_data(&ctrl->gc, ctrl);
if (err) {
dev_err(&pdev->dev,
"cannot add AR71xx GPIO chip, error=%d", err);
return err;
}
if (np && !of_property_read_bool(np, "interrupt-controller"))
return 0;
err = gpiochip_irqchip_add(&ctrl->gc, &ath79_gpio_irqchip, 0,
handle_simple_irq, IRQ_TYPE_NONE);
if (err) {
dev_err(&pdev->dev, "failed to add gpiochip_irqchip\n");
goto gpiochip_remove;
}
gpiochip_set_chained_irqchip(&ctrl->gc, &ath79_gpio_irqchip,
platform_get_irq(pdev, 0),
ath79_gpio_irq_handler);
return 0;
gpiochip_remove:
gpiochip_remove(&ctrl->gc);
return err;
}
更多推荐
已为社区贡献2条内容
所有评论(0)