Port B GPIO ep93xx/gpio.c interrupt issue - linux-kernel

I am having troubles with gpio interrupt issue.
According documentation for ep93xx ports A, B, F can be configured to generate interrupts.
quote:
Any of the 19 GPIO lines maybe configured to generate interrupts
However arch/arm/march-ep93xx/gpio.c is handling only interrupts from port A. And doesn't react to port B and F.
static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc)
{
unsigned char status;
int i;
printk(KERN_INFO "ep93xx_gpio_ab_irq_handler: irq=%u", irq);
I know printk is terrible in irq_handlers.
I am configuring iterrupts via sysfs.
GPIO 0,8 are wired with Port F if it is important to issue.
Also when enabling interrupts on port B without having configured port A i get following warning:
------------[ cut here ]------------
WARNING: at drivers/gpio/gpiolib.c:103 gpio_ensure_requested+0x54/0x118()
autorequest GPIO-1
Modules linked in:
[<c002696c>] (unwind_backtrace+0x0/0xf0) from [<c00399d4>] (warn_slowpath_fmt+0x54/0x78)
[<c00399d4>] (warn_slowpath_fmt+0x54/0x78) from [<c019dd90>] (gpio_ensure_requested+0x54/0x118)
[<c019dd90>] (gpio_ensure_requested+0x54/0x118) from [<c019e05c>] (gpio_direction_input+0xb0/0x150)
[<c019e05c>] (gpio_direction_input+0xb0/0x150) from [<c002c9a8>] (ep93xx_gpio_irq_type+0x3c/0x1d8)
[<c002c9a8>] (ep93xx_gpio_irq_type+0x3c/0x1d8) from [<c0066ad8>] (__irq_set_trigger+0x38/0x9c)
[<c0066ad8>] (__irq_set_trigger+0x38/0x9c) from [<c0066e14>] (__setup_irq+0x2d8/0x354)
[<c0066e14>] (__setup_irq+0x2d8/0x354) from [<c0066f38>] (request_threaded_irq+0xa8/0x140)
[<c0066f38>] (request_threaded_irq+0xa8/0x140) from [<c019e784>] (gpio_setup_irq+0x14c/0x260)
[<c019e784>] (gpio_setup_irq+0x14c/0x260) from [<c019ec1c>] (gpio_edge_store+0x90/0xac)
[<c019ec1c>] (gpio_edge_store+0x90/0xac) from [<c01be8fc>] (dev_attr_store+0x1c/0x28)
[<c01be8fc>] (dev_attr_store+0x1c/0x28) from [<c00e8b2c>] (sysfs_write_file+0x168/0x19c)
[<c00e8b2c>] (sysfs_write_file+0x168/0x19c) from [<c009a3d4>] (vfs_write+0xa4/0x160)
[<c009a3d4>] (vfs_write+0xa4/0x160) from [<c009a6a4>] (sys_write+0x3c/0x7c)
[<c009a6a4>] (sys_write+0x3c/0x7c) from [<c0020e40>] (ret_fast_syscall+0x0/0x2c)
---[ end trace ff56c09a294dbe68 ]---
I am using kernel version 2.6.34.14 with linux-2.6.34-ts7200_matt-6.tar.gz patch (hovewer it doesn't seem contain patches for gpio.c or gpiolib.c)
cross version:
binutils-2.23.1
gcc-4.7.3
glibc-2.17
Also i crawled through change history of gpio.c and gpiolib.c and didn't find anything that can be related to this issue.
Can someone give me and advice regarding this issue? I want interrupts on all ports (A,B,F) not just A.

There are a lot of question on this issue (and ARM irq OR interrupt). Please look at them.
We can see many changes by looking at more recent Linux 3.0 gpio.c change logs versus the 2.6.34 logs and the current version. You should be able to get the current Linux stable tree and extract these patches and back port them to your kernel. For instance, there is a bug where port C and F are swapped; I don't know if this is in your ts7200_matt variant.
Some important change sets to look at,
arm: Fold irq_set_chip/irq_set_handler
arm: Cleanup the irq namespace
arm: ep93xx: Use proper irq accessor functions
arm: ep93xx: Add basic interrupt info
ARM: ep93xx: irq_data conversion.
ARM: 5954/1: ep93xx: move gpio interrupt support to gpio.c
[ARM] 5243/1: ep93xx: bugfix, GPIO ports C and F are swapped
You may have #6, but it is worth looking at as it is basically the interrupt implementation for your controller. After about linux-3.0, your SOC's GPIO controller was moved to drivers/gpio/gpio-ep93xx.c. You may wish to look at these changes, but none seem to be related to your issue. You should be aware of structural changes to Linux. Ie, overall changes to interrupt handling and/or the generic GPIO infrastructure. A good guess is that Thomas Gleixner or Russell King will make these changes.
The patches can be extracted from a particular Linux stable tree with git format-patch b685004.. b0ec5cf1 gpio.c. This will create several patch files. Move them to your tree and apply with either git am or patch -p1. You may have to massage these files to get them to apply cleanly to your tree; if you take them all, even though they are not related to interrupt handling, you will have better luck doing this automatically. You can also look at the patch set and try to manually patch the file with a text editor.
None of this addresses your specific questions. However, it gives a path to merge changes from the latest Linux versions. Also, the previous stack overflow questions give details on the structure of the GPIO interrupt handling. Coupled with your data sheet, the Linux GPIO document, and the given change sets, you should be able to fix your own problem. Otherwise, you need someone familiar with the EP93xx and the question is fairly localized.
Note: The stack trace indicates that a GPIO is being used without a corresponding gpio_request()
. This is either a bug in the machine file or in the EP93xx GPIO interrupt handling code.

I had the same warning:
------------[ cut here ]------------
WARNING: at drivers/gpio/gpiolib.c:103 gpio_ensure_requested
From my research we have to call gpio_request_one / gpio_request, before gpio_direction_input.
It fixed the problem for me.
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=99789
http://e2e.ti.com/support/embedded/linux/f/354/p/119946/427889.aspx

Related

IRQ 8 request_irq, Operation not permitted

I'm new to kernel modules development and in my study process, I moved to the interrupts. My task is to write an interrupt handler module for IRQ 8, which will simply count the number of interrupts that occurred on this line and store the value in the kobject. The task sounds relatively easy at a first glance, but I've encountered strange behaviour. I wrote a handler function that simply increments the counter and returns interrupt as handled
static int ir=0;
static irq_handler_t my_handler(int irq_no, void *dev_id, struct pt_regs *regs)
{
ir++;
return (irq_handler_t) IRQ_HANDLED;
}
To hook the interrupt handler I call the request_irq() function inside my __init with the first argument being 8, so the IRQ 8 (which is reserved by rtc) line interrupts are handled
#define RTC_IRQ 8
[...]
int err;
err = request_irq(RTC_IRQ, (irq_handler_t) my_handler,IRQF_SHARED,"rtc0",NULL);
if (err != 0)
return -1;
With the implementation shown above, loading a kernel module gives me err equal to -22, which is EINVAL. After googling I discovered that for the IRQF_SHARED flag last parameter can't be assigned as NULL. I tried to find a method to obtain rtc->dev_id within the module, but in some of the examples they just typecasted the handler into (void *) so I tried passing (void *) my_handler. This gives me a flag mismatch warning on insmod
genirq: Flags mismatch irq 8. 00000080 (rtc0) vs. 00000000 (rtc0)
And err value set to -16, what I read from some sources means "busy". While trying to find a way to obtain a device-id I found out that interrupt is sent by the rtc0 device which is "inherited" from the rtc-cmos parent.
There are different controversial clues I found in different sources across the internet on this matter. Some state that the kernel disables rtc after the synchronization of the software clock, but this can't be the case, since the use of sudo bash -c ' echo +20 > /sys/class/rtc/rtc0/wakealarm ' and read of /proc/interrupts on the IRQ 8 line shows that interrupts are working as intended
Other sources state that all the request_irqs directed to the line must have the IRQF_SHARED flag installed to be able to share the interrupt line. Reading the source file for rtc-cmos gave me nothing since they are setting up interrupts via reading-writing CMOS directly
I spent a lot of time trying to figure out the solution to the problem, but it seems like the RTC interrupts aren't commonly used in a kernel modules development, so finding relevant and recent information on the case is difficult, most of the discussions and examples are related to the implementation when SA_SHIRQ-like flags were used and /drivers/examples folder was present in the kernel source files which is something around kernel version 2.6. And both interrupts and rtc kernel implementation were changed since those times
Any hints/suggestions that may help resolve this issue will be greatly appreciated. This is my first StackOverflow question, so if anything in its format is wrong or disturbing you are welcome to point it out in the comments as well
Thanks in advance for any help
I solved the problem quite a while ago now, but here's some explanation for newbies like me. #stark provided a good hint for the problem.
The main thing to understand is that irresponsible actions in the kernel space quickly lead to a "disaster" of sorts. Seemingly, this is the main reason Linux developers are closing more and more regions from the users/developers.
Read here for the solution
So, in modern kernel versions, you don't randomly tie the handler to a line and mark interrupts as resolved. But you still can "listen" to them using the IRQF_SHARED flag and at the end of your handler you let the interrupt untouched by returning IRQ_NONE, so you are not breaking the correct operation of the rest of the kernel if the interrupt is crucial for something else.
End of the solution, some extra advice on kernel development next
At the very start, it is important to understand that this is not a Userspace where your actions at most will lead to a memory leakage or corruption of some files. Here your actions will easily damage your kernel. If a similar scenario happened to Windows, you'll have no other choice than completely reinstalling the entire OS, but in GNU/Linux this is not really the case. You can swap to a different kernel without the need to go through a tedious process of recovering everything as was before, so if you are a hardcore enthusiast that's too lazy to use VMs, learning to swap kernels, will come in handy real soon:)

Where to find device-tree?

Coming form this question yesterday, I decided to port this library to my board. I was aware that I needed to change something, so I compiled the library, call it on a small program and see what happens. The 1st problem is here:
// Check for GPIO and peripheral addresses from device tree.
// Adapted from code in the RPi.GPIO library at:
// http://sourceforge.net/p/raspberry-gpio-python/
FILE *fp = fopen("/proc/device-tree/soc/ranges", "rb");
if (fp == NULL) {
return MMIO_ERROR_OFFSET;
}
This lib is aimed for Rpi, os the structure of the system on my board is not the same. So I was wondering if somebody could tell me where I could find this file or how it looks like so I can find it by my self in order to proceed the job.
Thanks.
You don't necessarily want that "file" (or more precisely /proc node).
The code this is found in is setting up to do direct memory mapped I/O using what appears to be a pi-specific gpio-flavored version of the /dev/mem type of device driver for exposing hardware special function registers to userspace.
To port this to your board, you would need to first determine if there is a /dev/mem or similar capability in your kernel which you can activate. Then you would need to determine the appropriate I/O registers for GPIO pins. The pi-specific code is reading the Device Tree to figure this out, but there are other ways, for example you can manually read the programmer's manual of the SoC on which you are running.
Another approach you can consider is adding some small microcontroller (or yes, barebones ***duino) to the system, and using that to collect information from various sensors and peripherals. This can then be forwarded to the SoC over a UART link, or queried out via I2C or similar - add a small amount of cost and some degree of bottleneck, but also means that the software on the SoC then becomes very portable - to a different comparable chip, or perhaps even to run on a desktop PC during development.

Failed to request_irq for kernel module

I am trying to port drivers from old kernel to new one on ARM based platform. While porting one of the drivers I have noticed that request_irq fails on new kernel. Actually, what this driver have is a number of hard coded irq numbers, and it tries to request_irq for this HW lines. I started to search what is the reason of request_irq failure, - the reason is that the appropriate IRQ descriptor (irq_desc) have IRQ_NOREQUEST flag set.
I started to search where this flag is cleared, and found that it happens here:
of_platform_populate
|
...
|
of_device_alloc
|
...
|
irq_of_parse_and_map
(some levels below this flag is dropped)
So that code is invoked from mach init code and parse DTB, all interrupt numbers that are mentioned in DTB would be mapped to irq virtual space and will be accessible through appropriate devices structures, for example:
irq = platform_get_irq(pdev, 0);
As I already said, this old - fashion drivers just have hard-coded irq numbers in include files, and they don't have no appropriate dtb entries.
The question is what is the right way, from the kernel perspective of view, to port this? Do I need to make this old driver a platform device (now it is just a char device) and create appropriate dtb description for it? Or I can just use some kernel API to mark this interrupts as available? Is it a common/normal style?

GPIO pins will not toggle (high/low) on beagleboard xm

I am trying to use the expansion header to control a couple motors and auxiliary task mechanism. For this I am using the appropriate pins as GPIO and merely attempting to send high or low signals as needed by the robot. (For instance, I might need the robot to move forward and so I'd send high signals on both sets of pins, whereas if I needed the robot to turn I'd send a high signal to one pin and a low to the other.)
However, the problem is that the pins will only stay high! I've followed the conventions for sysfs just via the terminal, and, although I'm able to set the "values", "active_lows", etc. to 0 or 1, I can't actually get the pins to send 0V. After checking the beagle.h file I used for u-boot it looks like the multiplexer mode is configured correctly. This is also reflected when I get the info from sys/class/gpio/gpio%/% and sys/kernel/debug/gpio. Furthermore I don't get any errors or indication from anywhere that there is something wrong...it just doesn't work!
What should I do? For the first time in my life I have seemingly exhausted the internet...
details:
Beagleboard xm rev c1
ubuntu 12.04
kernel 3.6.8-x4
Im pretty new to the beagle board and I have recently been trying to configure the GPIO pins on my classic beagleboard c4, which i believe should be fairly similar.
Half of my GPIO pins seemed to work fine and the other half seemed to remain high or low no matter what i did. Even though they were configured the same way as the working pins in /sys/class/gpio/
have you tried to use other gpio pins?
I ended up following http://labs.isee.biz/index.php/Mux_instructions
to configure the mux to 4 and now i can control the pins that were not working.
I basically used the command:
sudo echo 0x004 > /sys/kernel/debug/omap_mux/(mux 0 name)
where (mux 0 name) was the name of the subsystem for the mux 0 setting for the gpio pin you wish to configure
ie. for gpio 183 on beagleboard c4
sudo echo 0x004 > /sys/kernel/debug/omap_mux/i2c2_sda
Though I had to change permissions to modify these files
As I said I am pretty new to the beagleboard and ubuntu but this worked for me so I thought I would share it with you, I hope it is of some help.
Regards;
Paul;
It seems that the beagleboard expansion pins are numbered in alternating fashion, as clearly and professionally depicted here.
Thanks to everyone for your help. I now know way more than I should about GPIO on OMAP systems (and so do you). Good luck on finals/life!**
tl;dr I'm an idiot!

Kernel does NOT recognize NAND bad blocks marked by u-boot

While in u-boot of my ARM based board (DM368) I mark some kernel partition block manually as bad. U-boot says that it was marked and, for example, while writing/reading kernel image I see it skipping this bad block.
But when I try to write the same partition from within Linux (loaded via NFS) I see that Linux nandwrite command USES this bad block! I checked this in several ways - Linux ignores bad block mark for 100%. But everywhere in the internet it is said that BBT is one for both u-boot and Linux.
So, where is the catch?
OK, the answer is found.
For some unclear reason Texas Instruments, manufacturer of the board DM365EVM which I use for development, provides the kernel with different BBT structure. They defined BBT offset as 2, while all the world, including the provided u-boot, defines this offset as 8.
I wish them a good health for many years.

Resources