I'm trying to setup a MCP2515 CAN controller on the second SPI channel on an Onion Omega2 using the actual OpenWRT master (Kernel 5.4) . The SPI part is fine (half duplex mcp251x patch will be mainlined soon) as the controller initialization works:
but I'm struggeling with the GPIO IRQ part. I want to use GPIO16 for the MCP2515 interrupt.The DTS part looks like (according to the mcp251x devictree binding docs):
The problem is still present. I'm using the 21.02 branch and made some tests.
Using the GPIO 16 with IRQ on Falling Edge: interrupts = <16 0x02>
the IRQ appears on the right position but on wrong GPIO bank:
It's hanging now on line 759 where it disables the IRQ to initialize the MCP chip.
If you comment out this line it does successfully start the MCP chip and continue on into the rx/tx loop, HOWEVER it starts throttling since the irq is using 90% of the cpu.
I'm still investigating but I'm getting close I think.
Without any changes I was also able to setup the CAN interface. Until you don't send or receive any CAN frame anything looks fine. The problem begins, when the CAN controller generates the first interrupt (send or receive packet).
To investigate the problem I set the IRQ to falling edge, which isn't correct. It's need to be set to Level (low) for a fully working mcp251x module.
I got it working eventually, but it ended up being a mix of a couple different things. I ended up starting on 19.07 instead of the latest.
I only had to modify two files, if you don't count the kernel config, and the DTS file.
gpio-mt7621.c
Added LEVEL_LOW and LEVEL_HIGH triggers
mcp251x.c
Changed the flags from IRQF_ONESHOT | IRQF_TRIGGER_FALLING; to IRQF_ONESHOT | IRQF_TRIGGER_LOW
Added support for half duplex spi instead of full duplex, since this version of the mcp driver in the kernel didn't have it.
called gpio_request_one to set the interrupt since reading from the dts file didn't seem to work
explicitly set the freq due to the same issue as above.
I'm not honestly sure why reading the set values in the device tree didn't work but that was the last thing I needed before the driver started working.
Thank you very much for your response and most importantly for the glimmer of hope that you gave me after laterally pulling my hear.
Can you please share those two files as I'm not very familiar with how adding trigger works as well as adding support for half duplex SPI. It seems the driver version I'm using already supports half-duplex I added some printk during initialization to confirm that (I'm on 23.05):
You're on a different version of OpenWRT than I am, but what finally got everything working for me was directly requesting the GPIO as an interrupt using the gpio_request_one function.
I believe I got the mcp251x_can_ist to kick in but it's getting stuck/hanging on mutex_lock:
I saw that you experienced hanging issue. Was that due mutex_lock?
Also, did you end up changing the below? when I change girq->handle = handle_simple_irq;
to: girq->handle = handle_level_irq;
In my case if I change it to girq->handle = handle_level_irq and comment the mutex_lock my mcp251x_can_ist function keep triggering.
When I put the original girq->handle = handle_simple_irq; back i get the very first error [45798.219321] irq 41: nobody cared (try booting with the "irqpoll" option)
I know that I'm close but not sure where is the problem.
I got it to work. It was my mistake all along as I was setting my interrupt on the wrong gpio I also had to change girq->handle = handle_simple_irq to girq->handle = handle_level_irq. Thank you very much
Can you share your final changes? I'd like to update to the latest openwrt version if possible and that nobody cares message was the last thing that was hanging me up.
in drivers/gpio/gpio-mt7621.c change the following:
girq->handler = handle_simple_irq;
to
girq->handler = handle_level_irq;
in mcp251x.c I added the below changes:
#define GPIO_INT 491
....
/* in mcp251x_open function i forced the flags as below */
flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
/* in mcp251x_can_probe function I added the below */
ret = gpio_request_one(GPIO_INT, GPIOF_IN, "mcp2515_gpio");
if (ret) {
printk("gpio_request_one: %d", ret);
goto error_probe;
}
ret = gpio_to_irq(GPIO_INT);
if (ret < 0) {
printk("gpio_to_irq: %d", ret);
goto error_probe;
}
spi->irq = ret;
Just in case you need it my .dts file looks like this: