SAMA5D27 - pioA as Interrupt Parent

This forum is for users of Microchip MPUs and who are interested in using Linux OS.

Moderator: nferre

smvoss
Posts: 6
Joined: Wed Sep 19, 2018 8:16 pm

SAMA5D27 - pioA as Interrupt Parent

Wed Jun 05, 2019 4:17 pm

Good Morning,

The last few days I have been attempting to use the atmel pinctrl as the interrupt parent for an in-house driver, which wants to consume one of the GPIO's input as an interrupt.

I have tried many things, but the main things come down to:

Method 1: Using the base AIC as my interrupt parent:

Code: Select all

example_driver {
	compatible = "example_drv";
	pinctrl-0 = <&pinctrl_example_irq>;
	interrupts = <PIN_PC9 IRQ_TYPE_EDGE_RISING 7>;
	status = "okay";
};
With this, the platform_data struct contains a resource I would expect, named "/example_drv" and is an IRQ resource type. The driver will continue on, and successfully request the interrupt and it ends up in /proc/interrupt.

Code: Select all

 46:          0  atmel-aic5  57 Level     example-name
There is a button attached to this gpio (B25, #57) and when I press it the interrupt handler for my driver is not called.

Method 2: Using the pio as the interrupt parent:


After digging deeper, I found that the pinctrl is also an interrupt parent, so I decided to give that a shot. This time, I set up my device tree like:

Code: Select all

example_driver {
	compatible = "example_drv";
	pinctrl-0 = <&pinctrl_example_irq>;
        interrupt-parent = <&pioA>;
	interrupts = <PIN_PB25 IRQ_TYPE_EDGE_RISING>;
	status = "okay";
};
However, when I debug the driver there is no `struct resource*` in the `platform_data`. Just the sentinel. This means that `platform_get_irq` fails, cascading a new set of failures.

The one important piece of information I got from this, however, is if I use the `pinctrl` as my interrupt parent and hard code
my interrupt number using something like

Code: Select all

request_irq(gpio_to_irq(57), ....)
It actually hooks up, and pressing the button successfully calls my interrupt handler.

Code: Select all

103:          1      GPIO  57 Edge      example-name
Remaining thoughts

I think that using the pinctrl is the correct way, however I am having no luck actually passing this information in from my device tree, and outside of hardcoding this platform's setup into my driver isn't working the way I expect.

Thanks for the help
blue_z
Location: USA
Posts: 1976
Joined: Thu Apr 19, 2007 10:15 pm

Re: SAMA5D27 - pioA as Interrupt Parent

Thu Jun 06, 2019 8:16 am

smvoss wrote: The last few days I have been attempting to use the atmel pinctrl as the interrupt parent for an in-house driver, which wants to consume one of the GPIO's input as an interrupt.
You've apparently created an XY problem involving "AIC", "pioA", and "interrupt parent", when the basic issue seems to be using a GPIO as an interrupt source.
IOW you are trying to solve the wrong problems.

smvoss wrote: I think that using the pinctrl is the correct way, ...
No.
You stated upfront that you are using a GPIO, so interface with the Linux kernel's gpio subsystem, and not the pinctrl subsystem.

smvoss wrote: ...however I am having no luck actually passing this information in from my device tree, and outside of hardcoding this platform's setup into my driver isn't working the way I expect.
What information are you trying to pass?
What are your "expectations"?
If you want to use a GPIO as an interrupt source, then the pin number and interrupt characteristics (e.g. rising/falling edge) are the salient information to convey from the DT to the driver.

The DeviceTree is a description of your board.
You have only mentioned "an in-house driver" (but no device), a GPIO for an interrupt, and "pressing the button".
That is not much of a description to write a DT node.

You do not define "interrupt-parent" or "interrupt" properties for a DeviceTree node when there is no such hardware connection.

GPIO numbers are one-to-one mapped to "hardware" interrupt numbers.
That is what gpio_to_irq() is for.

If you're using a button as an event source, then consider defining the GPIO as a gpio-key.
Although primarily defined for userspace, the kernel documentation does mention its use in kernel space.
But I'm not aware of any examples.
Regardless you could use the code in gpio_keys_setup_key() in drivers/input/keyboard/gpio_keys.c as an example.

Regards
smvoss
Posts: 6
Joined: Wed Sep 19, 2018 8:16 pm

Re: SAMA5D27 - pioA as Interrupt Parent

Thu Jun 06, 2019 5:35 pm

What information are you trying to pass?
What are your "expectations"?
If you want to use a GPIO as an interrupt source, then the pin number and interrupt characteristics (e.g. rising/falling edge) are the salient information to convey from the DT to the driver.
You're right, I didn't clarify this well enough. Let me back up.

I have a kernel module, which has no external hardware component. This driver accepts a single interrupt source via GPIO, and modifies system state (which must happen in the kernel) on an edge. We use this across multiple other processors, I am just having an issue "hooking" the GPIO/interrupt into the driver on this platform.
What information are you trying to pass?
What are your "expectations"?
If you want to use a GPIO as an interrupt source, then the pin number and interrupt characteristics (e.g. rising/falling edge) are the salient information to convey from the DT to the driver.
This is exactly what I expected to happen, and had no luck getting to work. In general I would expect to add my interrupt, with a pin and it's characteristics to my device tree, and have the `struct resource*` of my `platform_device` to be populated with the information, and let me hook into it with `platform_get_device`, `platform_get_irq` etc.

This is not what I am seeing, and this is why I have had to start testing the different `interrupt-parents` (AIC vs pinctrl).
The DeviceTree is a description of your board.
You have only mentioned "an in-house driver" (but no device), a GPIO for an interrupt, and "pressing the button".
That is not much of a description to write a DT node.
Hopefully I made this part a little more clear, but to dive in a little deeper:

We have a second processor doing some work. That processor, occasionally needs to inform the sama5 of an event, which is picked up by our module. This event happens by driving an external pin low, causing a falling-edge interrupt on the main processor. If the event recovers, we will do the opposite and get a rising-edge.

The "button" mentioned before is just a way to test this in an easy software-less way. It isn't important in the grand-scheme of things, and I should have omitted it from my original post.
GPIO numbers are one-to-one mapped to "hardware" interrupt numbers.
That is what gpio_to_irq() is for.
I understand, which is why I "hardcoded" it with a gpio number, into the irq request. I shouldn't have to do this, I expect the device tree to be parsed and have the `struct resource*` contain an interruptable source, which I can claim in the driver (which is what is done on other platforms).

Hopefully this describes my problem a bit better than I was able to previously.
blue_z
Location: USA
Posts: 1976
Joined: Thu Apr 19, 2007 10:15 pm

Re: SAMA5D27 - pioA as Interrupt Parent

Fri Jun 07, 2019 1:13 am

smvoss wrote: I shouldn't have to do this, I expect the device tree to be parsed and have the `struct resource*` contain an interruptable source, which I can claim in the driver (which is what is done on other platforms).
I admit I'm hazy on how a platform data structure gets filled in by the DT. During the transition from board file to DT, you used to see driver code that parsed the DT and explicitly filled in its platform data structure (e.g. see this old article).

But that "old" technique is still used, e.g. Documentation/devicetree/bindings/mmc/atmel-hsmci.txt describes a cd-gpios property which is a GPIO used as an interrupt source.
Try adapting the following code excerpts from drivers/mmc/host/atmel-mci.c to your purpose:

Code: Select all

		pdata->slot[slot_id].detect_pin =
			of_get_named_gpio(cnp, "cd-gpios", 0);
...
	if (gpio_is_valid(slot->detect_pin)) {
		if (devm_gpio_request(&host->pdev->dev, slot->detect_pin,
				      "mmc_detect")) {
                ...
		}
	}
 ...
		ret = request_irq(gpio_to_irq(slot->detect_pin),
				atmci_detect_interrupt,
				IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
				"mmc-detect", slot);

For your situation replace "cd-gpios" with "int-gpios", and the DT node could be as simple as

Code: Select all

    example_driver {
	    compatible = "example_drv";
	    int-gpios = <&pioB 25 GPIO_ACTIVE_LOW>;
    };
(as a child node to whatever (?) parent node).

Regards
smvoss
Posts: 6
Joined: Wed Sep 19, 2018 8:16 pm

Re: SAMA5D27 - pioA as Interrupt Parent

Fri Jun 07, 2019 4:38 pm

I admit I'm hazy on how a platform data structure gets filled in by the DT. During the transition from board file to DT, you used to see driver code that parsed the DT and explicitly filled in its platform data structure (e.g. see this old article).
This is how I was able to "hardcode" it to work, and admittedly it's a fine solution. My only reservations are that this kernel/pinctrl are the only pair that I've had this issue on, and it seems like there may be a deficiency in a driver somewhere. I personally do not know these internals very well either, do you by chance have anyone else you could forward this onto to take a look?

Would be nice if this "just worked", but I am going to run with the `int-gpio` solution I have for now, as those holes go pretty deep.

Thanks for the help
abelloni
Posts: 17
Joined: Sat May 03, 2014 7:34 pm

Re: SAMA5D27 - pioA as Interrupt Parent

Thu Sep 12, 2019 9:18 pm

Here is a snippet of a module that works:

Code: Select all

#include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>

struct rttest {
	struct gpio_desc	*in;
	struct gpio_desc	*out;
};

static irqreturn_t rttest_irq(int irq, void *dev_id)
{
	struct rttest *rttest = dev_id;

	gpiod_set_value(rttest->out, 1);
	gpiod_set_value(rttest->out, 0);

	return IRQ_HANDLED;
}

static int test_probe(struct platform_device *pdev)
{
	struct rttest *rttest;
	int ret, irq;

	rttest = devm_kzalloc(&pdev->dev, sizeof(*rttest), GFP_KERNEL);
	if (!rttest)
		return -ENOMEM;

	rttest->in = devm_gpiod_get(&pdev->dev, "in", GPIOD_IN);
	if (IS_ERR(rttest->in))
		return PTR_ERR(rttest->in);

	rttest->out = devm_gpiod_get(&pdev->dev, "out", GPIOD_OUT_LOW);
	if (IS_ERR(rttest->out))
		return PTR_ERR(rttest->out);

	irq = gpiod_to_irq(rttest->in);
	ret = devm_request_irq(&pdev->dev, irq, rttest_irq,
				IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_NO_THREAD,
				"rttest", rttest);

	return ret;
}

#ifdef CONFIG_OF
static const struct of_device_id gpio_beeper_of_match[] = {
	{ .compatible = "rttest", },
	{ }
};
MODULE_DEVICE_TABLE(of, gpio_beeper_of_match);
#endif

static struct platform_driver rttest_driver = {
	.probe	= test_probe,
	.driver = {
		.name = "rttest",
		.of_match_table = of_match_ptr(gpio_beeper_of_match),
	},
};

module_platform_driver(rttest_driver);

MODULE_DESCRIPTION("RT Test driver");
MODULE_LICENSE("GPL v2");
And the accompanying DT snippet:

Code: Select all

       test {
               compatible = "rttest";
               pinctrl-names = "default";
               pinctrl-0 = <&pinctrl_gpio_test>;
               out-gpio = <&pioA PIN_PC0 0>;
               in-gpio = <&pioA PIN_PB31 0>;
       };
 

Return to “LINUX”

Who is online

Users browsing this forum: No registered users and 3 guests