Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/css/41.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
关于PCA9555扩展器上#中断单元配置的混淆_C_Linux_Linux Kernel_Interrupt_Device Tree - Fatal编程技术网

关于PCA9555扩展器上#中断单元配置的混淆

关于PCA9555扩展器上#中断单元配置的混淆,c,linux,linux-kernel,interrupt,device-tree,C,Linux,Linux Kernel,Interrupt,Device Tree,我第一次尝试在我的自定义平台上设置设备树源文件。主板上有一个NXP PCA9555 gpio扩展器。我正在尝试为设备设置节点,但有点困惑 下面是我在dts文件中使用节点的位置: ioexp0: gpio-exp@21 { compatible = "nxp,pca9555"; reg = <21>; interrupt-parent = <&gpio>; interrupts = <8 0&g

我第一次尝试在我的自定义平台上设置设备树源文件。主板上有一个NXP PCA9555 gpio扩展器。我正在尝试为设备设置节点,但有点困惑

下面是我在dts文件中使用节点的位置:

ioexp0: gpio-exp@21 {
        compatible = "nxp,pca9555";
        reg = <21>;

        interrupt-parent = <&gpio>;
        interrupts = <8 0>;

        gpio-controller;
        #gpio-cells = <2>;

        /*I don't understand the following two lines*/
        interrupt-controller;
        #interrupt-cells = <2>;
};

这是我第一次使用device tree,所以我希望它是我所缺少的东西。

在查看了所有评论之后,我做了一些额外的阅读并找到了我的答案

我现在明白了,我误解了设备树的一些属性。我以前的印象是,司机必须指定如何处理所有财产。我现在看到linux实际上将处理许多通用属性,例如
gpios
中断
(这很有意义)

关于实际的文档非常有用,而不是关于设备驱动程序的文档

下面更详细地解释了如何将intspec转换为
IRQ\u TYPE*

_irq_parse_one的函数
将中断说明符整数复制到\u phandle_args的
结构中。然后,该参数通过使用者函数(例如,获取irq的
)传递给irq映射的
。然后,此函数将这些参数通过\u phandle\u args\u to \u fwspec的
映射到
结构irq\u fwspec
,并将其fwspec数据传递到
irq\u create\u fwspec\u映射。这些函数都可以在中找到。此时,irq将属于
irq\u域
或使用
irq\u默认域
。据我所知,
pca853x
驱动程序使用默认域。此域通常由特定于平台的代码设置。我通过搜索
irq\u domain\u ops
找到了我的。其中许多似乎是通过
IRQ\u domain\u translate
intspec[1]&IRQ\u TYPE\u SENSE\u MASK
简单复制到
IRQ\u create\u fwspec\u mapping
中的
TYPE
变量。从这里,通过
irqd\u set\u trigger\u type
将类型设置为irq的
irq\u数据

的irq\u parse\u one

/**
 * of_irq_parse_one - Resolve an interrupt for a device
 * @device: the device whose interrupt is to be resolved
 * @index: index of the interrupt to resolve
 * @out_irq: structure of_irq filled by this function
 *
 * This function resolves an interrupt for a node by walking the interrupt tree,
 * finding which interrupt controller node it is attached to, and returning the
 * interrupt specifier that can be used to retrieve a Linux IRQ number.
 */
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
{
    struct device_node *p;
    const __be32 *intspec, *tmp, *addr;
    u32 intsize, intlen;
    int i, res;

pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);

/* OldWorld mac stuff is "special", handle out of line */
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
    return of_irq_parse_oldworld(device, index, out_irq);

/* Get the reg property (if any) */
addr = of_get_property(device, "reg", NULL);

/* Try the new-style interrupts-extended first */
res = of_parse_phandle_with_args(device, "interrupts-extended",
                "#interrupt-cells", index, out_irq);
if (!res)
    return of_irq_parse_raw(addr, out_irq);

/* Get the interrupts property */
intspec = of_get_property(device, "interrupts", &intlen);
if (intspec == NULL)
    return -EINVAL;

intlen /= sizeof(*intspec);

pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);

/* Look for the interrupt parent. */
p = of_irq_find_parent(device);
if (p == NULL)
    return -EINVAL;

/* Get size of interrupt specifier */
tmp = of_get_property(p, "#interrupt-cells", NULL);
if (tmp == NULL) {
    res = -EINVAL;
    goto out;
}
intsize = be32_to_cpu(*tmp);

pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);

/* Check index */
if ((index + 1) * intsize > intlen) {
    res = -EINVAL;
    goto out;
}

/* Copy intspec into irq structure */
intspec += index * intsize;
out_irq->np = p;
out_irq->args_count = intsize;
for (i = 0; i < intsize; i++)
    out_irq->args[i] = be32_to_cpup(intspec++);

/* Check if there are any interrupt-map translations to process */
res = of_irq_parse_raw(addr, out_irq);
 out:
    of_node_put(p);
    return res;
}
EXPORT_SYMBOL_GPL(of_irq_parse_one)

我认为您必须查看
中断父级的设备树绑定,它看起来是设备树中某个位置的gpio节点。这可能会对您有所帮助:您的gpio扩展器有一条到主机的中断线,并支持作为中断控制器。所以,这意味着,如果您将pin设置为中断源,它将生成链接到平台上PIC的中断。这就是为什么这两行出现在DTS中。
/**
 * of_irq_parse_one - Resolve an interrupt for a device
 * @device: the device whose interrupt is to be resolved
 * @index: index of the interrupt to resolve
 * @out_irq: structure of_irq filled by this function
 *
 * This function resolves an interrupt for a node by walking the interrupt tree,
 * finding which interrupt controller node it is attached to, and returning the
 * interrupt specifier that can be used to retrieve a Linux IRQ number.
 */
int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
{
    struct device_node *p;
    const __be32 *intspec, *tmp, *addr;
    u32 intsize, intlen;
    int i, res;

pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);

/* OldWorld mac stuff is "special", handle out of line */
if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
    return of_irq_parse_oldworld(device, index, out_irq);

/* Get the reg property (if any) */
addr = of_get_property(device, "reg", NULL);

/* Try the new-style interrupts-extended first */
res = of_parse_phandle_with_args(device, "interrupts-extended",
                "#interrupt-cells", index, out_irq);
if (!res)
    return of_irq_parse_raw(addr, out_irq);

/* Get the interrupts property */
intspec = of_get_property(device, "interrupts", &intlen);
if (intspec == NULL)
    return -EINVAL;

intlen /= sizeof(*intspec);

pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);

/* Look for the interrupt parent. */
p = of_irq_find_parent(device);
if (p == NULL)
    return -EINVAL;

/* Get size of interrupt specifier */
tmp = of_get_property(p, "#interrupt-cells", NULL);
if (tmp == NULL) {
    res = -EINVAL;
    goto out;
}
intsize = be32_to_cpu(*tmp);

pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);

/* Check index */
if ((index + 1) * intsize > intlen) {
    res = -EINVAL;
    goto out;
}

/* Copy intspec into irq structure */
intspec += index * intsize;
out_irq->np = p;
out_irq->args_count = intsize;
for (i = 0; i < intsize; i++)
    out_irq->args[i] = be32_to_cpup(intspec++);

/* Check if there are any interrupt-map translations to process */
res = of_irq_parse_raw(addr, out_irq);
 out:
    of_node_put(p);
    return res;
}
EXPORT_SYMBOL_GPL(of_irq_parse_one)
unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
{
    struct irq_domain *domain;
    struct irq_data *irq_data;
    irq_hw_number_t hwirq;
    unsigned int type = IRQ_TYPE_NONE;
    int virq;

    if (fwspec->fwnode) {
        domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
        if (!domain)
            domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_ANY);
    } else {
        domain = irq_default_domain;
    }

    if (!domain) {
        pr_warn("no irq domain found for %s !\n",
            of_node_full_name(to_of_node(fwspec->fwnode)));
        return 0;
    }

    if (irq_domain_translate(domain, fwspec, &hwirq, &type))
        return 0;

    /*
     * WARN if the irqchip returns a type with bits
     * outside the sense mask set and clear these bits.
     */
    if (WARN_ON(type & ~IRQ_TYPE_SENSE_MASK))
        type &= IRQ_TYPE_SENSE_MASK;

    /*
     * If we've already configured this interrupt,
     * don't do it again, or hell will break loose.
     */
    virq = irq_find_mapping(domain, hwirq);
    if (virq) {
        /*
         * If the trigger type is not specified or matches the
         * current trigger type then we are done so return the
         * interrupt number.
         */
        if (type == IRQ_TYPE_NONE || type == irq_get_trigger_type(virq))
            return virq;

        /*
         * If the trigger type has not been set yet, then set
         * it now and return the interrupt number.
         */
        if (irq_get_trigger_type(virq) == IRQ_TYPE_NONE) {
            irq_data = irq_get_irq_data(virq);
            if (!irq_data)
                return 0;

            irqd_set_trigger_type(irq_data, type);
            return virq;
        }

        pr_warn("type mismatch, failed to map hwirq-%lu for %s!\n",
            hwirq, of_node_full_name(to_of_node(fwspec->fwnode)));
        return 0;
    }

    if (irq_domain_is_hierarchy(domain)) {
        virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec);
        if (virq <= 0)
            return 0;
    } else {
        /* Create mapping */
        virq = irq_create_mapping(domain, hwirq);
        if (!virq)
            return virq;
    }

    irq_data = irq_get_irq_data(virq);
    if (!irq_data) {
        if (irq_domain_is_hierarchy(domain))
            irq_domain_free_irqs(virq, 1);
        else
            irq_dispose_mapping(virq);
        return 0;
    }

    /* Store trigger type */
    irqd_set_trigger_type(irq_data, type);

    return virq;
}
EXPORT_SYMBOL_GPL(irq_create_fwspec_mapping);