将设备树中断标志映射到devm_request_irq

时间:2016-10-13 03:25:49

标签: linux-kernel linux-device-driver device-tree

我目前正在为Linux使用PowerPC编写设备驱动程序。

设备树条目如下:

// PPS Interrupt client 
pps_hwirq {
    compatible = "pps-hwirq";
    interrupts = <17 0x02>;                     // IPIC 17 = IRQ1, 0x02 = falling edge
    interrupt-parent = < &ipic >;
};

0x02标志非常重要 - PPS与下降沿对齐,但这在GPS接收器上并不通用,因此应该是可配置的。

在驱动程序的probe()函数中,获取IRQ编号非常简单:

hwirq = irq_of_parse_and_map(np, 0);
if (hwirq == NO_IRQ) {
    dev_err(&pdev->dev, "No interrupt found in the device tree\n");
    return -EINVAL;
}

但是如何将IRQ标志从设备树映射到驱动程序?

/* ****TODO****: Get the interrupt flags from the device tree 
 * For now, hard code to suit my problem, but since this differs
 * by GPS receiver, it should be configurable.
 */
flags = IRQF_TRIGGER_FALLING;

/* register IRQ interrupt handler */
ret = devm_request_irq(&pdev->dev, data->irq, pps_hwint_irq_handler,
                       flags, data->info.name, data);

不幸的是,树中实际执行此工作的示例很少 - 如果有的话 - 大多数将此标记保留为0(保持原样) - 这是grep devm_request_irq时的结果片段1}},注意标志的值:

./drivers/crypto/mxs-dcp.c:     ret = devm_request_irq(dev, dcp_vmi_irq, mxs_dcp_irq, 0,
./drivers/crypto/mxs-dcp.c:     ret = devm_request_irq(dev, dcp_irq, mxs_dcp_irq, 0,
./drivers/crypto/omap-sham.c:   err = devm_request_irq(dev, dd->irq, dd->pdata->intr_hdlr,
./drivers/crypto/omap-aes.c:            err = devm_request_irq(dev, irq, omap_aes_irq, 0,
./drivers/crypto/picoxcell_crypto.c:    if (devm_request_irq(&pdev->dev, irq->start, spacc_spacc_irq, 0,

或硬编码硬件实际断言的内容:

./drivers/crypto/tegra-aes.c:   err = devm_request_irq(dev, dd->irq, aes_irq, IRQF_TRIGGER_HIGH |

那么如何将这个属性从设备树干净地关联到实际的驱动程序呢?

1 个答案:

答案 0 :(得分:5)

此外,我将展示如何在一些常见情况下从设备树获取IRQ号和IRQ标志:

  • in I2C drivers
  • 在平台驱动程序中
  • 手动

在I2C驱动程序中

简而言之

如果您正在编写I2C驱动程序,则无需手动从DT读取IRQ参数。您可以依靠I2C内核为您填充IRQ参数:

    您的probe()函数中的
  • client->irq将包含IRQ编号
  • devm_request_irq()将自动使用DT的IRQ标志(只是不要将任何IRQ触发器标志传递给该函数)。

详细信息

让我们看一下i2c_device_probe()函数(它是你的驱动程序probe()函数的调用位置):

static int i2c_device_probe(struct device *dev)
{
    ...
    if (dev->of_node) {
        ...
        irq = of_irq_get(dev->of_node, 0);
    }
    ...
    client->irq = irq;
    ...
    status = driver->probe(client, i2c_match_id(driver->id_table, client));
}

因此,client->irq已经在您的驱动程序的探测函数中包含IRQ编号。

至于IRQ标志:of_irq_get()(在上面的代码中)最终调用irqd_set_trigger_type(),它在内部存储IRQ标志(从设备树读取)作为中断号。因此,当您致电devm_request_irq()时,它最终会以__setup_irq()结束,然后会执行下一步:

/*
 * If the trigger type is not specified by the caller,
 * then use the default for this interrupt.
 */
if (!(new->flags & IRQF_TRIGGER_MASK))
    new->flags |= irqd_get_trigger_type(&desc->irq_data);

其中:

  • new->flags包含您向devm_request_irq()
  • 提供的标记
  • irqd_get_trigger_type()返回从DT
  • 获得的标志

换句话说,如果你没有将IRQ标志传递给devm_request_irq()(例如传递0),它将使用从设备树获得的IRQ标志。

有关详细信息,另请参阅this question

在平台驱动程序中

您可以使用platform_get_irq()获取IRQ号码。它还存储(内部)从DT获得的IRQ标志,因此如果您将flags=0传递给devm_request_irq(),将使用DT中的标志。

手动

如果您的驱动程序不依赖于内核框架,则必须手动获取IRQ值:

  • 可以通过irq_of_parse_and_map()获得IRQ号码(如您所述);此函数不仅返回IRQ号,还存储IRQ号的IRQ标志(最终通过调用irqd_set_trigger_type());存储的IRQ标记将自动用于devm_request_irq(),如果您没有向其传递IRQ触发类型(例如,您可以通过flags=0
  • IRQ标志可以通过irq_get_trigger_type()获取,但仅在执行irq_of_parse_and_map()

    之后

    因此,您可能只需要运行irq_of_parse_and_map()并让devm_request_irq()为您处理标记(只需确保不要将触发标记传递给它)。