Hello!
I am developing a GPT linux device driver for a specific project we have. I have a working driver that can configure, start and stop the timer, and various other things. The next thing I need is to trigger an interrupt on an input capture
event. The input capture works and I have enabled the IC1IE flag in the GPT.
The linux-device-driver registers the irq routine using the following snippet:
uint8_t minor_num = 1;
uint8_t* minor_num_p = &minor_num;
if (request_irq(IRQ_NUMBER, irq_handler, IRQF_SHARED, "gpt_device", (void *)(minor_num_p))) {
printk(KERN_ALERT "FAILED TO SETUP IRQ ");
goto fail;
}
The irq_handler function is a simple printk statement for now.
In /proc/interrupts
the handler seems to have been registered as there is a new entry:
IRQ_NUMBER: 0 0 0 0 0 0 GICv3 442 Level gpt_device
The device-tree entry for the gpt has an interrupts
parameters:
lsio_gpt1: gpt@5d150000 {
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
....
};
I believe this one should be 18 since the apalis iMX8 datasheet says that the ALT3 function is _IO18
.
I am very unsure of the IRQ_NUMBER for the linux-device-driver (a bit for the device-tree as well). According to the i.MX8QM reference manual, GPT1_INT is 113, but I have not gotten the interrupt to work yet. Is there another value I should use? Or are there any other settings that I need to set in hardware? I tried to look into the GIC and IRQ_STEER as those where the ones that seemed to control the interrupts, but they seem to be more for the m4 cores. I am used to having to modify an NVIC when working on interrupts, but have not found anything like that for the iMX8QM
Hardware details:
Apalis IMX8QM using the ixoraV1.2 board
Best regards,
Hi @aleksw
I guess you want to get the interrupt for GPT1 if I understand you correctly not for a GPIO, right?
According to the reference manual that would be GIC_SPI 113 as you write. However, you have to subtract 32 to map with the NXP Linux numbering. So it would be:
lsio_gpt1: gpt@5d150000 {
interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
....
};
Regards,
Stefan
Thanks for your response @stefan_e.tx!
Alrighty, I didnt know about the subtraction of 32. Then the values of the device-tree actually makes a lot more sense.
But what number should I use for ny linux driver then? I tried to use 81 as the IRQ_NUMBER in the request_irq(), but then I get this error:
[ 5.484001] genirq: Flags mismatch irq 81. 00000084 (gpt_device) vs. 00000004 (5b040000.ethernet)
Hi @aleksw
You shouldn’t just put a number in there. The device has several interrupt controllers that’s why you have to use the device tree to get to the right number. Use e.g. platform_get_irq_byname to get the correct interrupt:
I would recommend you to get familiar with device trees, else it will be hard to succeed with the driver. I can recommend you Bootlin as a training partner for these topics:
Regards,
Stefan
Hello @aleksw,
I hope you are doing well. May I know if you were able to make any progress on this topic?
So @stefan_e.tx was onto something with the suggestion of using the function platform_get_irq_by_name
, however, since I am developing a normal linux device driver and not a platform driver, Im not sure that I could use this method. There is a different set of functions that can be used to get information from the device-tree and map that into linux values. So I got the interrupt to work in the using the following:
struct device_node* device_tree_node = NULL;
device_tree_node = of_find_node_by_name( NULL, "gpt1" );
if ( device_tree_node == NULL ) {
printk( KERN_ALERT "Device tree node: %s is not defined in DTS\n", "gpt1" );
return -1;
}
int irq_number = irq_of_parse_and_map( device_tree_node, 0 );
if ( request_irq(irq_number, irq_handler, IRQF_SHARED, "interrupt_routine_name",
(void*)( &interrupt_data ) ) ) {
printk( KERN_ALERT "FAILED TO SETUP IRQ %i", irq_number );
return -1;
}
Where gpt1
is the node name infront of the physical memory specialization(I was not able to use any other names or labels to acquire this information)
lsio_gpt1: gpt1@5d150000 {
interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
};
And the irq_handler
has a signature of:
static irqreturn_t irq_handler( int irq, void* dev_id ) {}
In the end, using interrupts for measuring the frequency of an external signal was not a reliable method when the frequency got too high. So i ended up using the external signal as the an external clock for the signal and then counting the number of ticks that happens in a given amount of time, which works surprisingly well 