I am currently writing a device driver for Linux for use of PowerPC.
The device tree entry is as follows:
// PPS Interrupt client
pps_hwirq {
compatible = "pps-hwirq";
interrupts = <17 0x02>; // IPIC 17 = IRQ1, 0x02 = falling edge
interrupt-parent = < &ipic >;
};
The 0x02 flag is quite important - the PPS is aligned with the falling edge, but this is not universal on GPS receivers and therefore should be configurable.
In the probe()
function of the driver, obtaining the IRQ number is straightforward:
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;
}
But how does one map the the IRQ flags from the device tree to the driver?
/* ****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);
Unfortunately, there are few - if any - examples in the tree that actually do this job - most leave this flag as 0 (leave as-is) - here's a snippet of the results when grep
for devm_request_irq
, noting the values for the flags:
./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,
Or hard code it to what the hardware actually asserts:
./drivers/crypto/tegra-aes.c: err = devm_request_irq(dev, dd->irq, aes_irq, IRQF_TRIGGER_HIGH |
So how does one cleanly associate this property from the device tree to the actual driver?
Further I'm gonna show how to obtain IRQ number and IRQ flags from Device Tree in some common cases:
If you're writing an I2C driver, you don't need to read IRQ parameters from DT manually. You can rely on I2C core to populate IRQ parameters for you:
probe()
function, client->irq
will contain the IRQ numberdevm_request_irq()
will use IRQ flags from DT automatically (just don't pass any IRQ trigger flags to that function).Let's look at the i2c_device_probe() function (it's where your driver's probe()
function is being called from):
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));
}
So, client->irq
will already contain IRQ number in your driver's probe function.
As for IRQ flags: of_irq_get()
(in code above) eventually calls irqd_set_trigger_type()
, which internally stores IRQ flags (read from device tree) for your interrupt number. So, when you call devm_request_irq()
, it eventually ends up in __setup_irq()
, and it does next:
/*
* 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);
where:
new->flags
contains flags you provided to devm_request_irq()
irqd_get_trigger_type()
returns flags obtained from DTIn other words, if you don't pass IRQ flags to devm_request_irq()
(e.g. pass 0), it will use IRQ flags obtained from device tree.
See also this question for details.
You can use platform_get_irq()
to obtain IRQ number. It also stores (internally) IRQ flags obtained from DT, so if you pass flags=0
to devm_request_irq()
, flags from DT will be used.
If your driver doesn't rely on kernel frameworks, you have to obtain IRQ values manually:
IRQ number can be obtained (as you mentioned) by irq_of_parse_and_map()
; this function not only returns IRQ number, but also stores IRQ flags for your IRQ number (by calling irqd_set_trigger_type()
eventually); stored IRQ flags will be automatically used in devm_request_irq()
, if you don't pass IRQ trigger type to it (e.g. you can pass flags=0
)
IRQ flags can be obtained by irq_get_trigger_type(), but only after executing irq_of_parse_and_map()
So probably you only need to run irq_of_parse_and_map()
and let devm_request_irq()
handle flags for you (just make sure you don't pass trigger flags to it).