Getting Linux IRQ number from hardware IRQ number - linux

I have a GPIO peripheral, defined in Device Tree as that:
gpio0: gpio#2300000
{
compatible = "fsl,qoriq-gpio";
reg = <0x0 0x2300000 0x0 0x10000>;
interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
I want to write an interrupt handler for this (as a kernel module). But this IRQ number (66) is a hardware one and I need a virtual, Linux IRQ number to pass it to request_irq.
How can I get this number? There is only one interrupt controller (GIC).
Is there a way to do this without writing a platform device driver (as there is probably already one working in the system and I think I cannot register another one).

As per you comment you want to register a GPIO as an interrupt.
The node of device tree that you have posted is the interrupt controller node, which wont concern us for the task we have at hand.
To register a gpio as an interrupt, you first need to find a GPIO which can be configured as an interrupt (in most modern processors all GPIOs support it) and then you have to make sure it is not used by some other device by multiplexing it (if it is used by some one like SPI or UART etc , you can disable them from device tree if you are not using that entity).
now that you have a GPIO pin that you can use. Find the GPIO number on kernel that pin corresponds to (it depends on the architecture of your processor and its carrier board).
When you have that you can just write a simple module that will export your GPIO and use it as interrupt.
Below is a snippet from http://derekmolloy.ie
gpio_request(gpioButton, "sysfs"); // Set up the gpioButton
gpio_direction_input(gpioButton); // Set the button GPIO to be an input
gpio_set_debounce(gpioButton, 200); // Debounce the button with a delay of 200ms
gpio_export(gpioButton, false); // Causes gpio115 to appear in /sys/class/gpio
// the bool argument prevents the direction from being changed
// Perform a quick test to see that the button is working as expected on LKM load
printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpioButton));
// GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
irqNumber = gpio_to_irq(gpioButton);
printk(KERN_INFO "GPIO_TEST: The button is mapped to IRQ: %d\n", irqNumber);
// This next call requests an interrupt line
result = request_irq(irqNumber, // The interrupt number requested
(irq_handler_t) ebbgpio_irq_handler, // The pointer to the handler function below
IRQF_TRIGGER_RISING, // Interrupt on rising edge (button press, not release)
"ebb_gpio_handler", // Used in /proc/interrupts to identify the owner
NULL); // The *dev_id for shared interrupt lines, NULL is okay
Link to the complete code.

For whom is not trying to create a GPIO driver but still need to get Linux virtual IRQ from HW IRQ, there is a specific API for platform drivers. You can register a platform driver and then, during the probing, call
/**
* platform_get_irq - get an IRQ for a device
* #dev: platform device
* #num: IRQ number index
*
* Gets an IRQ for a platform device and prints an error message if finding the
* IRQ fails. Device drivers should check the return value for errors so as to
* not pass a negative integer value to the request_irq() APIs.
*
* Return: non-zero IRQ number on success, negative error number on failure.
*/
int platform_get_irq(struct platform_device *dev, unsigned int num);
Detailed explanation
To reach your goal, you have a lot of different options:
GPIO Driver Interface (GPIO drivers providing IRQs)
Low-level OF API for Device Trees (of_irq_get)
Device drivers' infrastructure API (platform_get_irq)
GPIO Driver Interface
If your platform has a programmable GPIO, you can use the GPIO Driver Interface. See #yashC reply. In your specific case, given that your device is part of GPIO, you should go for this approach.
Low-level Device Trees APIs
If you want to interact directly with the device tree, you can use this solution. Imho, you should follow this approach only if you are writing a specific (and non-generic) driver and you need a "dirty and clean" way to go.
static const struct of_device_id qoriq_gpio_match_table[] =
{
{ .compatible = "fsl,qoriq-gpio" },
{ }
};
np = of_find_matching_node(NULL, qoriq_gpio_match_table);
if (!np)
{
pr_err("No device tree node for qoriq-gpio\n");
return -ENODEV;
}
// decode a node's IRQ and return it as a Linux IRQ number
irq_num = of_irq_get(np, 0);
// request_irq(...)
Device drivers' infrastructure API
Basically, you have to register a platform driver.
static const struct of_device_id qoriq_gpio_match_table[] =
{
{ .compatible = "fsl,qoriq-gpio" },
{ }
};
static struct platform_driver qoriq_gpi_driver = {
.driver = {
.name = "qoriq-gpio",
.of_match_table = qoriq_gpio_match_table
},
.probe = qoriq_gpio_probe
};
static int qoriq_gpio_probe(struct platform_device *pdev)
{
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
// request_irq(...)
}
Until Kernel v5.19 you were able to use also: platform_get_resource(pdev, IORESOURCE_IRQ, 0); API that, currently, is no more available.
You should use this approach if your device is a bit more generic (eg. you are working with several boards with different DTs).

Related

SPI conflict between SD.h and U8x8.h (LCD)

I want to reproduce a .wav file on my Arduino Uno via an SD card while at the same time using an LCD display (Nokia 5110). I'm having trouble trying to make the double SPIs work and since I'm not really familiar with the libraries that I used I decided to ask for help
The problem is that once the program execute SD.begin() the display stops working and the SPI communication is working only on the SD.
In this setup that I'm showing I will initialize the SD in the setup() and in the loop using a button I'm supposed to write stuff on the display:
//Libraries
#include <U8x8lib.h>
#include <SPI.h>
#include "SD.h"
#include "TMRpcm.h"
//Display (pin 13, pin 11, pin A1, pin 12, pin A0 )
U8X8_PCD8544_84X48_4W_SW_SPI lcd(LCD_CLK, LCD_DIN, LCD_CE, LCD_DC, LCD_RST);
//Speaker
TMRpcm music;
void setup() {
//Serial port -> Open
Serial.begin(9600);
while (!Serial) {}
//LCD
display_setup();
//SD and Speaker
sdAndSpeaker_setup();
}
void loop() {
topButton.poll();
if (topButton.buttonClicked) {
display_something();
}
}
Ignore the function related to the button, I removed most of its code to avoid cluttering the page.
Here's when the problem occurs:
void sdAndSpeaker_setup() {
music.speakerPin = 10;
// (pin 4)
if (!SD.begin(SD_CS)) {
Serial.println("SD fail");
Serial.flush();
abort();
}
music.setVolume(4);
music.play("Daybreak.wav");
music.quality(2);
}
I know that by changing the pins of display to other value (rather than 11, 12 and 13) the problems is solved but most of the pins in my board are already used and I don't have this luxury... I think this has something to do with the U8x8.h and SD.h library but I don't have the skills to tweak those.
If anyone has a suggestion I'll appreciate!
Thanks!
EDIT:
Thanks to Juraj for the clarification, here's my new changes for the corrected constructor:
U8X8_PCD8544_84X48_4W_HW_SPI lcd(LCD_CE, LCD_DC, LCD_RST);
And for the setup_display()
void display_setup() {
lcd.begin();
pinMode(LCD_LIGHT, OUTPUT);
digitalWrite(LCD_LIGHT, HIGH);
lcd.setFont(u8x8_font_chroma48medium8_r);
lcd.drawString(1,2, "Hello!");
}
Unfortunately it still doesn't work...
The constructor
U8X8_PCD8544_84X48_4W_SW_SPI(uint8_t clock, uint8_t data, uint8_t cs, uint8_t dc, uint8_t reset = U8X8_PIN_NONE)
creates a 'driver' which uses software SPI. But you supply pins of hardware SPI as parameters. Hardware SPI is used by the SD library over the SPI library to access the SD card, so hardware SPI conflicts with the software SPI of the display library.
There is a
U8X8_PCD8544_84X48_4W_HW_SPI(uint8_t cs, uint8_t dc, uint8_t reset = U8X8_PIN_NONE)
constructor which uses the hardware SPI over the SPI library. The SPI library 'knows' the pin numbers of the SPI pins. (SPI library is part of the boards package. It can't be installed separately.)
If you want to use the software SPI, use free pins. The hardware SPI uses pins 11, 12, 13 on Uno.

linux device driver control high-speed SPI ADC

Recently I have a project to use a Linux host to communicate with an ADC device(SPI communication). I use my knowledge to write a device driver for it.
The goal of this driver is to read ADC data and transfer them to userspace. My idea is when the Linux host gets the DRDY signal(data ready signal, the signal means the data of ADC can be read) from ADC, an interrupt will be triggered, and the SPI read API of the driver will read data from the SPI bus. the data will fill into a buffer, when the buffer is full, the driver sends a SIGNAL to the userspace program, and the data in the buffer will be read by the userspace.
Although this idea may not be a perfect plan to realize my goal, I finish the code above. Unfortunately, I face a question that makes my goal failed.
The SPI transfer API of the Linux host should be put into the bottom half of the interrupt(due to the sleep mechanic of SPI API), that is to say, if the sample rate of AD is too fast, the bottom half of the interrupt may read a delayed data of ADC, when I use 4kHz sample rate, there are 7997 interrupts, but only 7907 data has been read. When I use the 250Hz sample rate, my idea is OK. But, I must use at least 4ksps.
I do not know whether you have some experience with this kind of problem, or maybe my idea is not suited for the high-speed ADC, I hope you can give me some suggestions, thanks a lot.
Here is some core code of my idea. The SPI transfer function:
int get_ad_data(struct spi_device *ad_spi_dev)
{
int ret = -1;
gpio_set_value(ADS1299_CS_PIN, 0);
if( ad_spi_dev )
{
struct spi_transfer tr =
{
.tx_buf = &send_data,
.rx_buf = &get_data,
.len = 27,
};
ret = spi_sync_transfer(ad_spi_dev, &tr, 1);
}
printk("%02x, %02x, %02x\r\n",get_data[6],get_data[7],get_data[8]);
gpio_set_value(ADS1299_CS_PIN, 1);
return ret;
}
The interrupt handler:
static irqreturn_t drdy_handler(int irq, void *dev_id)
{
struct ads1299_dev *dev = dev_id;
schedule_work(&dev->drdy_irq.work_drdy);
return IRQ_HANDLED;
}
static void drdy_work(struct work_struct *work)
{
int ret;
ret = get_ad_data(ads1299_spi_dev);
}

Setting GPIO status during boot process

I have an Intel Galileo board with LED connected to one of GPIO pin. When I am connecting power to Galileo, LED lights up for a second and then turns off again.
Once my application start I am able to manipulate LED. But now I want my LED to turned ON during whole boot process and once my application starts it should manipulate LED after then. I guess to achieve this I have to change kernel code and build it again completely.
If possible, you can make the default state of the GPIO high/low in Boot loader. Or, Refer the following Changes in linux kernel and device tree.
:arch/xxx/boot/dts/xxxx.dts
led#4 {
label = "evmsk:green:heartbeat";
gpios = <&gpio1 7 0>;
linux,default-trigger = "heartbeat";
default-state = "off";
};
:drivers/leds/leds-gpio.c
state = of_get_property(child, "default-state", NULL);
if (state) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
led.default_state = LEDS_GPIO_DEFSTATE_ON;
else
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);

Kernel driver, ioremap necessary in MMU-less system?

So, I am a total newbie when it comes to kernel drivers and have a question regarding ioremap function.
I am writing a driver for accessing some registers defined in a custom VHDL-module on a SoC with a ARM Cortex-M3 and FPGA fabric.
Looking at examples I figured I should use ioremap, but since the Cortex-M3 does not have a MMU, I don't really see the point, as per the following example:
/* Physical addresses */
static u32* rcu_trig_recv_physaddr = ((u32 *) 0x50040000);
static int rcu_trig_recv_size = 0x10; // size of 16 for testing
/* Virtual addresses */
static u32* rcu_trig_recv_virtbase = NULL;
/*removed code not relevant for the question*/
static int __init rcumodule_init(void)
{
int iResult = 0; // holding result of operations
u32 buffer;
// Register the driver
iResult = register_chrdev(rcuc_majorID, "rcuc", &rcuc_fops);
if (iResult < 0) {
printk(KERN_INFO "module init: can't register driver\n");
}
else{
printk(KERN_INFO "module init: success!\n");
}
// Map physical address to virtual address
if(rcu_trig_recv_size){
rcu_trig_recv_virtbase = (u32*) ioremap_nocache( (u32 *)rcu_trig_recv_physaddr, rcu_trig_recv_size );
printk("Remapped TRGRECV from 0x%p to 0x%p\n", rcu_trig_recv_physaddr, rcu_trig_recv_virtbase);
}
// try to read some stuff, expecting 0x17240f09
buffer = readl(rcu_trig_recv_virtbase);
printk("read %lx, at 0x%p\n", buffer, rcu_trig_recv_virtbase);
return iResult;
}
This then return, when I insmod the driver:
# insmod trigger.ko
module init: success!
Remapped TRGRECV from 0x50040000 to 0x50040000
read 17240f09, at 0x50040000
According to this, I would just be better off reading the physical address instead. Or is that a bad idea and I should be messing with my registers in a better way?
It's possible that you can get away with this if you know your code will never need to be used on another device, but you're much safer sticking with using ioremap(). Basing your code around obtaining and using the pointers provided by memory-mapped IO will make your code more portable and maintainable than utilizing hard-coded physical addresses.
Even if you don't plan on taking this code to a different device, using physical addresses could potentially break your code when simply upgrading to a newer chip in the same line.

Linux External Event Handling - IRQ vs. Polling kthread

I am porting a device driver from QNX to Linux. In QNX, the old driver used a pthread with an infinite loop to monitor for the occurrence of an interrupt, rather than registering a true interrupt handler. To try to demonstrate the efficacy of using register_irq() instead of a dedicated polling thread, I wrote two drivers in Linux. The relevant code for each is shown below and the question is at the bottom.
IRQ
Write the handler
irqreturn_t timing_interrupt_handler(int irq, void *dev_id) {
u32 test;
/* read device interrupt command/status register */
test = ioread32(timing_card[3].base);
/* sanity check that the device reported the interrupt */
if ( test & (1 << 2) ) {
/* clear interrupt status */
iowrite32( 0x0d, timing_card[3].base);
/* toggle digital output line */
test = ioread32(timing_card[2].base);
if ( test & 0x01 )
iowrite32(test & ~0x1, timing_card[2].base);
else
iowrite32(test | 0x1, timing_card[2].base);
}
return IRQ_HANDLED;
}
Register the handler
rc = request_irq(irq_line, timing_interrupt_handler,
IRQF_SHARED, "timing", timing_card);
if ( rc ) {
printk(KERN_ALERT "Failed to register irq %d\n", irq_line);
return rc;
}
POLLING THREAD
Write the thread function
int poll_irq(void *data) {
u32 test;
/* until module unload */
while ( !kthread_should_stop() ) {
/* read device interrupt command/status register */
test = ioread32(timing_card[3].base);
/* sanity check that the device reported the interrupt */
if ( test & (1 << 2) ) {
/* clear interrupt status */
iowrite32( 0x0d, timing_card[3].base);
/* toggle digital output line */
test = ioread32(timing_card[2].base);
if ( test & 0x01 )
iowrite32(test & ~0x1, timing_card[2].base);
else
iowrite32(test | 0x1, timing_card[2].base);
}
else
usleep_range(9, 11);
}
return 0;
}
Begin the thread
kthread = kthread_create(poll_irq, 0x0, "poll_IRQ_test");
wake_up_process(kthread);
THE QUESTION
When I put two traces on an oscilloscope - one monitoring the card's digital input (which would trigger the interrupt) and one monitoring the card's digital output (which would react to the interrupt) I can measure the reaction time to an event.
The first "proper" method, registering an IRQ, takes approximately 80 microseconds.
The second method, running an infinite thread, takes approximately 15-30 microseconds.
What gives? The benefit of the first is that it doesn't waste as much processing power, but why does response time suffer so dramatically? How bad is it, really, to have this polling thread? How could one go about investigating and eventually demonstrating the extra toll the polling thread puts on the CPU?
Thanks for your time!
Best
Scott
The interrupt response time is affected by the time your system (whatever it is) needs to deliver the interrupt, and by the time your CPU (whatever it is) needs to wake up from some power-saving sleeping mode.
The polling thread eats both CPU time and power.
To measure them, use something like top or powertop, or measure the power consumption directly on the hardware.

Resources