Device tree interrupt to Linux GPIO


I’m trying to get a Maxim 17048 fuel gauge working on Hikey960. Working back from the error to the question:

[    7.004368] modelgauge 0-0036: IC production version 0x0012
[    7.021556] genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq 289
[    7.029534] modelgauge 0-0036: failed to request irq 289

The strange is, as far as I know, I’m not requesting irq 289. Looking at the spreadsheet that has been useful for me in getting other devices going:

We’re in Linux (Android) therefore irq 289 is SPI2_CS_N, so it makes sense that the request fails. But I wasn’t planning on using that pin (12) on the LS port for my fuel gauge interrupt. Instead I am using pin 24 (GPIO_209 aka GPIO_B). From this thread:

I learned that I can calculate the interrupt port like this:

parent = gpio / 8 ; 209 / 8 = 26
port = gpio % 8 ; 209 % 8 = 1

So I have this in my device tree node:

modelgauge@36 {
	compatible = "maxim,max17048";
	reg = <0x36>;
	interrupt-parent = <&gpio26>;
	interrupts = <1 0x2>; 

Now the question is, why does this translate into Linux gpio 289? From the spreadsheet I assume it would be gpio 297? I have similar code in drivers and dts for a Himax touchscreen controller which works perfectly fine.

– edit –

hmm I changed the DT into interrupt-parent = <&gpio27>; and now it maps to Linux GPIO 297. Still not sure why the caluclation doesn apply. Anyway IRQ request still fails. I’m not going to spend too much time trying to fix this as I am not actually planning to use this part and driver, I just happened to have it on a breakout. Without the IRQ it looks to be doing something, which was the goal of this hack :slight_smile:

[    7.021556] genirq: Threaded irq requested with handler=NULL and !ONESHOT for irq 289

Your IRQ initialization fails because you fall in this code (cf source comment):

This is the global IRQ number allocated to this interrupt by Linux, not the IRQ index of the specific interrupt/gpio controller. (cat /proc/interrupts gives you the matching).




I think I’m kind of getting the idea. However, would you have any suggestions regarding debugging issue around interrupts that are supposed to be happening, but are not getting picked up by the HiKey?

This time I have an Invensense IMU hooked up on I2C. You can set a data rate, say 10Hz. Now the IMU will pull its interrupt high every 10th of a second. A thread running on the SoC will stall until data is ready to be read from the IMU. I though I had the whole thing set up correctly, and on my scope I can see the interrupt going high every 10th of a second, but my data reading thread keeps blocking in the poll call. I’ve got the interrupt set up like this:

icm20602@68 {
	compatible = "inven,icm20602";
	reg = <0x68>;
	interrupt-parent = <&gpio26>;
	interrupts = <4 IRQ_TYPE_EDGE_RISING>;

So that would be pin 27.

cat proc/interrupts gives me this, so that looks ok:

294:          0          0          0          0          0          0          0          0     pl061   4 Edge      inv_mpu

I’ve got a test program running that correctly initializes the IMU, but then stalls in the poll(iiofd) call. My guess is that the pin 27 going high is not detected, probably because it’s not configured as an input? I have see drivers where an interrupt pin is forced to be an input via gpio and an additional dts entry, but this driver doesn’t have this. Is there a way I can check the current configuration of the GPIO pins? I scanned through the pinctrl dts files but i don really follow what is going on there…

– update –

Ok i fiddled around a bit with different pins on the LS connector and it started working. For some reason pin 27 is the only one I got it to work with. I had that one reserved for a different device, so I would like to understand why an IRQ request to any other of the LS GPIO pins fails.


Which kernel version you are running? If it is > 4.9, you can install libgpiod tool and use it for testing the interrupt capability of LS GPIO pins. Otherwise, use the sysfs interface for triggering an interrupt. If it works fine with manual testing then your DTS entry is suspicious.


Ok I found another one that works (GPIO-J aka GPIO_019 aka parent &gpio2 int 3). But for example, when I tried GPIO-L, the enable_irq request works, but when I monitor the signal on my scope, the interrupt signal only gets pulled to about 1V instead of 1.8V as if the pin is configured with a pull-down. I should be able to reconfigure the pin config in the driver code, shouldn’t I?


That doesn’t appear to be an upstream driver. What driver are you trying to use for it?

Datasheet for the max17048 describes the ALRT (interrupt) pin as active LOW. The max17048 itself is incapable of pulling the line high. Do those pins (i.e., GPIO-L) actually have an internal pull-up? Because if not, then you MUST apply external pull-up. In fact, if you are designing a mezzanine, it would be mandatory to add the external pull-up, regardless of the presence of pull-up on the SoC you are currently working with, since there is NO requirement or recommendation for provisioning the GPIO pins with pull-up. The only pull-up recommendation for the LS port specified is for the I2C pins.


O sorry I wasn’t talking about the fuel gauge any longer. I just happened to have that particular IC in a drawer on a breadboard and found a driver online. For the actual mezzanine we’re building I’ll choose a fuel gauge with upstream support.

The last post was related to the icm20602 accel/gyro. It has a rising edge interrupt.

Generally speaking, it confuses me why some pins on the LS connector can be used as interrupt pins, while others can’t. How and where can I see which ones will work and why?


Well, I would imagine that if its only making it to 1.0 volt, its just not getting to the threshold for logic high (probably around 1.2-1.3 volt). You might be right then, about it having a pull-down activated.


All GPIO pins are interrupt capable(GPIOA - GPIOL). What sort of driver is that? IIO? What are the flags you are passing for the request_irq function?


Yes it is IIO. This is the request_irq call:

ret = request_irq(st->irq, &iio_trigger_generic_data_rdy_poll,
		  IRQF_TRIGGER_RISING, "inv_mpu", st->trig);