Raspberry PI 3 - Kernel Driver - cannot access GPIO with ioremap() - c++

I'm trying to write a kernel driver (module) that reads GPIO on a RPI3
I use ioremap to get access to the memory of the GPIO, but apparently it crashes.
I get an exception in the /var/log/messages log file
Aug 6 14:07:58 raspberrypi kernel: [ 220.900252] Exception stack(0xa796ffa8 to 0xa796fff0)
Aug 6 14:07:58 raspberrypi kernel: [ 220.900264] ffa0: fe5f5100 7eff8714 00000003 0002d064 00000000 00000004
Aug 6 14:07:58 raspberrypi kernel: [ 220.900277] ffc0: fe5f5100 7eff8714 0003fce8 0000017b 007e47d8 00000000 00000002 00000000
Aug 6 14:07:58 raspberrypi kernel: [ 220.900286] ffe0: 7eff8548 7eff8538 00022cb8 76cb9af0
Here is my module code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/io.h>
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
static int __init driver_init(void)
{
if ((gpio = ioremap(GPIO_BASE, 0xB0)) == NULL) {
printk(KERN_INFO "io remap failed\n");
return -EBUSY;
}
return 0;
}
static void __exit driver_exit(void)
{
iounmap(gpio);
}
module_init(driver_init);
module_exit(driver_exit);
Can someone tell me what I do wrong?
Is there a conflict with another driver? How can I check this?

base adress is 0x3F000000, not 0x2000000

Related

Segfault when reading ELF Shdr of own executable

I'm trying to read the symbol table of the program's own ELF binary as part of a symbolizer. Part of this involves finding the ELF start, then ELF shdr, etc. I must be doing something wrong, though, because despite e_shoff matching what I see by readelfing the binary manually and the start address looking reasonable, I cannot read the shdr.
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <assert.h>
#include <dlfcn.h>
#include <elf.h>
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
static int findELFStartCallback(struct dl_phdr_info *info, size_t size,
void *data) {
static_cast<void>(size);
static int address_found = 0;
if (address_found) {
return 0;
}
address_found = 1;
fprintf(stderr, "relocation: 0x%lx\n", (long)info->dlpi_addr);
for (ElfW(Half) i = 0; i < info->dlpi_phnum; i++) {
if (info->dlpi_phdr[i].p_type == PT_LOAD) {
auto result = reinterpret_cast<void *>(info->dlpi_addr +
info->dlpi_phdr[i].p_vaddr);
fprintf(stderr, "a.out loaded at %p\n", result);
*reinterpret_cast<void **>(data) = result;
break;
}
}
return 0;
}
static void *findELFStart() {
void *result = nullptr;
dl_iterate_phdr(findELFStartCallback, &result);
return result;
}
static void checkELF(ElfW(Ehdr) * ehdr) {
assert(ehdr->e_ident[EI_MAG0] == ELFMAG0 && "bad magic number");
assert(ehdr->e_ident[EI_MAG1] == ELFMAG1 && "bad magic number");
assert(ehdr->e_ident[EI_MAG2] == ELFMAG2 && "bad magic number");
assert(ehdr->e_ident[EI_MAG3] == ELFMAG3 && "bad magic number");
}
int main(int argc, char *argv[]) {
char *exe_ = nullptr;
exe_ = reinterpret_cast<char *>(findELFStart());
assert(exe_ != nullptr && "could not find ELF header");
checkELF(reinterpret_cast<ElfW(Ehdr) *>(exe_));
auto elf = reinterpret_cast<ElfW(Ehdr) *>(exe_);
fprintf(stderr, "e_shoff is %ld (0x%lx)\n", elf->e_shoff, elf->e_shoff);
auto shdr = reinterpret_cast<ElfW(Shdr) *>(exe_ + elf->e_shoff);
fprintf(stderr, "shdr is %ld (%p)\n", (size_t)shdr, (void*)shdr);
const char *str = exe_ + shdr[elf->e_shstrndx].sh_offset; // boom
}
I get a segfault. When I load it in GDB, it looks like shdr is indeed a bad pointer. What am I missing here?
Sample output:
computer% ./p/dladdr
relocation: 0x0
a.out loaded at 0x400000
e_shoff is 24528 (0x5fd0)
shdr is 4218832 (0x405fd0)
zsh: segmentation fault (core dumped) ./p/dladdr
computer%
EDIT: After seeing Reading ELF header of loaded shared object during runtime maybe the sections just aren't loaded into memory...
EDIT: I finished the symbolizer and it's available here
maybe the sections just aren't loaded into memory...
That's exactly right. Here is readelf -WS /bin/date on my system:
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 0] NULL 0000000000000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 0000000000000318 000318 00001c 00 A 0 0 1
[ 2] .note.gnu.property NOTE 0000000000000338 000338 000050 00 A 0 0 8
[ 3] .note.gnu.build-id NOTE 0000000000000388 000388 000024 00 A 0 0 4
[ 4] .note.ABI-tag NOTE 00000000000003ac 0003ac 000020 00 A 0 0 4
...
[26] .bss NOBITS 000000000001a0a0 019098 000130 00 WA 0 0 32
[27] .gnu.build.attributes NOTE 000000000001c1d0 019098 000248 00 0 0 4
[28] .gnu_debuglink PROGBITS 0000000000000000 0192e0 000024 00 0 0 4
[29] .gnu_debugdata PROGBITS 0000000000000000 019304 0005a0 00 0 0 1
[30] .shstrtab STRTAB 0000000000000000 0198a4 00013e 00 0 0 1
Note that .shstrtab does not have the A (allocated) flag. The contents of this section is not used at runtime, so there is no reason to load it into memory, and so it isn't.
If you want to access .shstrtab, you need to either read it from the file on disk, or mmap the entire file (the kernel only mmaps the parts covered by PT_LOAD segments, not the entire file).

Why does INCBIN`d var throw an error when accessed?

VSCode, PlatformIO
ESP8266 nodeMCU v3.0
PIO`s INCBIN lib https://github.com/AlexIII/incbin-arduino?utm_source=platformio&utm_medium=piohome
I load by INCBIN lib one file to ESP8266.
I try to print first datum.
#include "Arduino.h"
#include "incbin.h"
INCBIN(my, "path/to/file.someExtension");
void setup()
{
Serial.begin(9600);
Serial.println();
Serial.println(*gmyData)
}
void loop(){}
monitor out
Exception (3):
epc1=0x40201098 epc2=0x00000000 epc3=0x00000000 excvaddr=0x40238b14 depc=0x00000000
LoadStoreError: Processor internal physical address or data error during load or store
epc1=0x40201098 in setup at ??:?
excvaddr=0x40238b14 in ethernet_input at ??:?
>>>stack>>>
ctx: cont
sp: 3ffffe00 end: 3fffffc0 offset: 0190
3fffff90: 3fffdad0 00000000 3ffee534 40201093
3fffffa0: feefeffe feefeffe 3ffee66c 40201e00
3fffffb0: feefeffe feefeffe 3ffe85d8 40100cc1
<<<stack<<<
0x40201093 in setup at ??:?
0x40201e00 in loop_wrapper() at core_esp8266_main.cpp:?
0x40100cc1 in cont_wrapper at ??:?
This also throws error.
uint8_t datum = *gmyData;
Serial.println(datum);
edit
Tests show that Serial.println() is not guilty. It's all about incbin'd var access.
test, which throws aforementioned exception:
int i;
if (*gmyData > 0)
i = 1;
else
i = 2;
Serial.println(i);
File is a "primary" certificate gtsltsr.crt from point 1.b from https://cloud.google.com/iot/docs/how-tos/mqtt-bridge#using_a_long-term_mqtt_domain
I tried to read first byte in main code sample just to check correctness.

Create an Arduino ESP8266 library

I would like to create a Arduino library for an ESP8266or ESP32 microcontroller. I wrote a test library which running on an Arduino Nano board with no problem. Here the library cpp file:
#include "Test.h"
Test::Test(){
}
uint32_t Test::libTest(strcttest* t){
uint32_t w;
w = t->a;
return w;
}
Here's the the header file :
#include <Arduino.h>
typedef struct {
uint32_t a;
uint32_t b;
}strcttest;
class Test
{
public:
Test();
uint32_t libTest(strcttest* t);
private:
};
And last but not least the Arduino ino file:
#include <Test.h>
//Instante Test
Test t;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("Start");
}
void loop() {
// put your main code here, to run repeatedly:
//Create structure
strcttest *tt;
tt->a=1;
tt->b=2;
//Output result
Serial.println (t.libTest(tt));
delay(1000);
}
Every compile fine with an Arduino Nano board as well as with ESP8266/ESP32 boards. When I run it on the Nano Board i get the expected result:
Start
1
1
1
1
1
1
1
1
1
...
When I run it on the ESP8266 board I get the following crash result:
l*⸮⸮⸮⸮CI>⸮⸮⸮HB⸮⸮Start
Exception (28):
epc1=0x402024f8 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
ctx: cont
sp: 3ffef7d0 end: 3ffef9a0 offset: 01a0
>>>stack>>>
3ffef970: feefeffe 00000000 3ffee950 40201eb4
3ffef980: feefeffe feefeffe 3ffee96c 40202340
3ffef990: feefeffe feefeffe 3ffee980 40100108
<<<stack<<<
7!a!*6⸮⸮⸮Start
Exception (28):
epc1=0x402024f8 epc2=0x00000000 epc3=0x00000000 excvaddr=0x00000000 depc=0x00000000
ctx: cont
sp: 3ffef7d0 end: 3ffef9a0 offset: 01a0
>>>stack>>>
3ffef970: feefeffe 00000000 3ffee950 40201eb4
3ffef980: feefeffe feefeffe 3ffee96c 40202340
3ffef990: feefeffe feefeffe 3ffee980 40100108
<<<stack<<<
ĜBs⸮`⸮"⸮⸮Start
...
And last but not least on the ESP Development board I receive:
i%M/⸮`⸮i%M7
⸮⸮%Q=qU=\Md⸮aGd<$⸮Start
Guru Meditation Error of type LoadProhibited occurred on core 1. Exception was unhandled.
Register dump:
PC : 0x400dde93 PS : 0x00060030 A0 : 0x800d0570 A1 : 0x3ffc7390
A2 : 0x3ffc1c30 A3 : 0x00000000 A4 : 0x0800001c A5 : 0xffffffff
A6 : 0xffffffff A7 : 0x00060d23 A8 : 0x800832e9 A9 : 0x3ffc7380
A10 : 0x00000003 A11 : 0x00060023 A12 : 0x00060020 A13 : 0x00000003
A14 : 0x00000001 A15 : 0x00000000 SAR : 0x0000001f EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000 LBEG : 0x400014fd LEND : 0x4000150d LCOUNT : 0xffffffff
Backtrace: 0x400dde93:0x3ffc7390 0x400d0570:0x3ffc73b0 0x400d79b0:0x3ffc73d0
CPU halted.
So my question is: What I am doing wrong. What do i miss. What I haven't understood with Arduino IDE, cpp, pointers, etc.
Sorry I forgot: I use Arduino IDE 1.8.2
strcttest *tt; is your problem. You're not allocating memory for and creating an object of type strcttest - you're merely allocating memory for a pointer to an object of that type. Basically, the code should crash everywhere when your code gets to the line tt->a=1; The fact that it doesn't when run on the Nano is basically dumb luck..
Think of the case where you have a char* variable and then try to copy a string to it - it will crash too, since you dont have any storage space for the string itself - you only have a few bytes allocated that store the address of the string.
The following is a more reasonable implementation of your void loop() function:
void loop() {
// put your main code here, to run repeatedly:
//Create structure
strcttest tt;
tt.a=1;
tt.b=2;
//Output result
Serial.println (t.libTest(&tt));
delay(1000);
}
Another (slower, due to use of new and delete) implementation may look like this:
void loop() {
// put your main code here, to run repeatedly:
//Create structure
strcttest *tt = new strcttest;
tt->a=1;
tt->b=2;
//Output result
Serial.println (t.libTest(tt));
delete tt;
delay(1000);
}
For ESP32 and ESP8266, have a excellent tool to help in crashes situations,
like that You report.
This integrates to Arduino IDE
See it in: https://github.com/me-no-dev/EspExceptionDecoder

Nouveau kernel rejected pushbuf on Allegro5-C++

I'm in trouble with this:
I've installed Allegro5 on Ubuntu, and compiled my Helloworld project
#include <allegro5\allegro.h> #include <allegro5\allegro_native_dialog.h> int main(void) {
ALLEGRO_DISPLAY *display=NULL;
if(!al_init()) {
al_show_native_message_box(NULL, NULL, NULL, "failed to initialize allegro!", NULL, NULL);
return -1;
}
display=al_create_display(640,
480);
if(!display) {
al_show_native_message_box(NULL, NULL, NULL, "failed to initialize display!", NULL, NULL);
return -1;
}
al_destroy_display(display);
return 0;
}
with " g++ -Wall TestProgram.cc pkg-config --libs allegro-5.0 allegro_font-5.0 allegro_ttf-5.0 ".
Running it on terminal, it gives me this error (or crash?) message:
nac#NAC:~$ ./a.out
nouveau: kernel rejected pushbuf: Bad file descriptor
nouveau: ch0: krec 0 pushes 1 bufs 1 relocs 0
nouveau: ch0: buf 00000000 00000002 00000004 00000004 00000000
nouveau: ch0: psh 00000000 00000004a8 00000004bc
nouveau: 0x00107b00
nouveau: 0x00000000
nouveau: 0x20217000
nouveau: 0x00000003
nouveau: 0x1000f010
After some tests I saw that it crashes on or after "al_destroy_display(display);", in fact, after that error I must ctrl+C to end the program.
How can I do??
This question is a few months old, but it comes up as the first hit when searching for this error. I had the same error running LinuxMint 17.2 with Allegro 5.0.10, and solved it by updating my graphics card (GeForce GTX 460) driver. Hope this helps future users.
I had a similar problem with Rstudio (it is quite famous bug on rstudio)
It is proposed to run it using the following command in terminal:
QT_XCB_FORCE_SOFTWARE_OPENGL=1 rstudio
so, in your case i think:
QT_XCB_FORCE_SOFTWARE_OPENGL=1 ./a.out

BeagleBone Black interrupts through kernel driver

I'm trying to work with interruptions but I get the following error, due to ioread32.
As I have seen in the chapter "25.3.3 Interrupt Features" of "AM335x SitaraTM Processors - Technical Reference Manual"
In order to generate an interrupt request to a host processor upon a defined event (level or logic transition) occurring on a GPIO pin, the GPIO configuration registers have to be programmed as follows:
• Interrupts for the GPIO channel must be enabled in the GPIO_IRQSTATUS_SET_0 and/or GPIO_IRQSTATUS_SET_1 registers.
• The expected event(s) on input GPIO to trigger the interrupt request has to be selected in the GPIO_LEVELDETECT0, GPIO_LEVELDETECT1, GPIO_RISINGDETECT, and GPIO_FALLINGDETECT registers.
[ 1737.604270] Loading hello_interrupts module...
[ 1737.604426] HI: Initialized GPIO #36 to IRQ #164
[ 1737.604478] Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa1ac02c
[ 1737.612611] Internal error: : 1028 [#1] SMP THUMB2
[ 1737.617696] Modules linked in: hello_interrupts(O+) g_multi libcomposite omap_rng mt7601Usta(O) [last unloaded: hello_interrupts]
[ 1737.630128] CPU: 0 Tainted: G O (3.8.13-bone67 #1)
[ 1737.636513] PC is at hello_interrupts_start+0x8b/0x123 [hello_interrupts]
[ 1737.643717] LR is at _raw_read_unlock+0x7/0x8
[ 1737.648340] pc : [<bf8f508c>] lr : [<c04cfaf7>] psr: 80000033
[ 1737.648340] sp : df3fde60 ip : 00000034 fp : c006a001
[ 1737.660481] r10: 00000001 r9 : de594200 r8 : bf8f5001
[ 1737.666011] r7 : 00000000 r6 : bf8f30b8 r5 : 00000000 r4 : fa1ac000
[ 1737.672920] r3 : 48000000 r2 : 00000000 r1 : 481adfff r0 : fa1ac000
[ 1737.679839] Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA Thumb Segment user
[ 1737.687569] Control: 50c5387d Table: 9f740019 DAC: 00000015
[ 1737.693655] Process insmod (pid: 3040, stack limit = 0xdf3fc240)
[ 1737.700025] Stack: (0xdf3fde60 to 0xdf3fe000)
[ 1737.704659] de60: bf8f30b8 00000000 00400100 df3fc000 c08b5740 c000867f 00000000 de5c3640
[ 1737.713323] de80: 00000000 00000000 00400100 bf8f326c bf8f3260 00000001 bf8f32a8 00000001
[ 1737.721988] dea0: c006a001 c006bd31 bf8f326c 00007fff c0069101 e0dd7000 e0dd6fff bf8f3260
[ 1737.730655] dec0: 00000000 b6f7dd50 df3fc000 bf8f33b4 e0dd6691 c02520d0 6e72656b 00006c65
[ 1737.739320] dee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1737.747993] df00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1737.756662] df20: 00000000 00000000 00000000 c0790a68 20000033 000016a8 b6fa2000 b6f7dd50
[ 1737.765331] df40: 00000080 c000c9e4 df3fc000 00000000 00000000 c006c26f e0dd5000 000016a8
[ 1737.774000] df60: e0dd5ae0 e0dd599f e0dd64c8 000003c8 000004c8 00000000 00000000 00000000
[ 1737.782670] df80: 0000001c 0000001d 00000014 00000012 00000010 00000000 00000000 b6fc0088
[ 1737.791339] dfa0: b6fc0d00 c000c841 00000000 b6fc0088 b6fa2000 000016a8 b6f7dd50 00000002
[ 1737.800008] dfc0: 00000000 b6fc0088 b6fc0d00 00000080 00000000 b6f7dd50 000016a8 00000000
[ 1737.808671] dfe0: 00000000 beb7969c b6f77b07 b6f01fd4 80000010 b6fa2000 c0c92420 c0c92440
[ 1737.817378] [<bf8f508c>] (hello_interrupts_start+0x8b/0x123 [hello_interrupts]) from [<c000867f>] (do_one_initcall+0x1f/0xf4)
[ 1737.829367] [<c000867f>] (do_one_initcall+0x1f/0xf4) from [<c006bd31>] (load_module+0x10d5/0x15b0)
[ 1737.838872] [<c006bd31>] (load_module+0x10d5/0x15b0) from [<c006c26f>] (sys_init_module+0x63/0x88)
[ 1737.848379] [<c006c26f>] (sys_init_module+0x63/0x88) from [<c000c841>] (ret_fast_syscall+0x1/0x46)
[ 1737.857867] Code: 4825 f3d4 debb e036 (6ac5) f3bf
[ 1737.884765] ---[ end trace cbd53ac03b070f86 ]---
This is my code:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
MODULE_AUTHOR("MGE");
MODULE_DESCRIPTION("A sample driver using interrupts");
MODULE_LICENSE("GPL");
// GPIO Bank 2
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
// GPIO memory-mapped register addresses.
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define PIN_A_GPIO 36
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id) {
printk (KERN_INFO "Hello from irq_handler_pin_a...\n");
return IRQ_HANDLED;
}
static int __init hello_interrupts_start (void) {
int retval, irq, regval;
void __iomem *mem;
printk (KERN_INFO "Loading hello_interrupts module...\n");
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);
if (retval) {
printk (KERN_ERR "HI: Error: Failed to request GPIO pin#%i for IRQ (error %i)\n", PIN_A_GPIO, retval);
// return -retval;
}
irq = gpio_to_irq (PIN_A_GPIO);
if (irq < 0) {
printk (KERN_ERR "HI: ERROR: Failed to obtain IRQ number for GPIO #%i (error %i)\n", PIN_A_GPIO, irq);
// return -irq;
}
retval = request_irq (irq, irq_handler_pin_a, 0 /*IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING*/, PIN_A_LABEL, NULL);
irq_set_irq_type (irq, IRQ_TYPE_EDGE_BOTH);
if (retval) {
printk (KERN_ERR "HI: ERROR: The requested IRQ line#%i from GPIO#%i (error %i)\n", irq, PIN_A_GPIO, retval);
// return -retval;
}
else {
printk (KERN_INFO "HI: Initialized GPIO #%i to IRQ #%i\n", PIN_A_GPIO, irq);
}
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
if(!mem) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for GPIO Bank 2 IRQ pin configuration.\n");
return 0;
}
// Enable the IRQ ability for GPIO_66.
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO_66 for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_FALLINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_FALLINGDETECT);
// Release the mapped memory.
iounmap (mem);
return 0;
}
static void __exit hello_interrupts_end(void) {
printk ("HI: Releasing IRQ resources...\n");
free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
gpio_free (PIN_A_GPIO);
printk (KERN_INFO "Goodbye hello_interrupts!\n");
}
module_init (hello_interrupts_start);
module_exit (hello_interrupts_end);
Any idea?
Thanks
The problem was that the GPIO2 module clocks was disabled.
"8.1.12.1.30 CM_PER_GPIO2_CLKCTRL Register (offset = B0h) [reset = 30000h]" of "AM335x SitaraTM Processors - Technical Reference Manual"
Bits 1-0:
Control the way mandatory clocks are managed.
0x0 = DISABLED : Module is disable by SW. Any OCP access to module results in an error, except if resulting from a module wakeup (asynchronous wakeup).
0x1 = RESERVED_1 : Reserved
0x2 = ENABLE : Module is explicitly enabled. Interface clock (if not used for functions) may be gated according to the clock domain state. Functional clocks are guarantied to stay present. As long as in this configuration, power domain sleep transition cannot happen.
0x3 = RESERVED : Reserved
For the above code to work, the GPIO2 clock has to be enabled using the CM_PER_GPIO2_CLKCTRL register and a GPIO pin from GPIO2 has to be choosen. In the code above, GPIO 36 was used, which is on GPIO1 (and anyway used by the internal flash). The following code enables the GPIO2 clock and uses GPIO 68 (which is on header P9 pin 10 btw):
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
MODULE_AUTHOR("MGE");
MODULE_DESCRIPTION("A sample driver using interrupts");
MODULE_LICENSE("GPL");
// GPIO Bank 2
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)
// CM_PER (Clock Module Peripheral Registers
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE 0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0
// GPIO memory-mapped register addresses.
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C
#define PIN_A_GPIO 68 // is on P9 pin 10
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"
static irqreturn_t irq_handler_pin_a (int irq, void *dev_id) {
printk (KERN_INFO "Hello from irq_handler_pin_a...\n");
return IRQ_HANDLED;
}
static int __init hello_interrupts_start (void) {
int retval, irq, regval;
void __iomem *mem;
void __iomem *cm_per;
printk (KERN_INFO "Loading hello_interrupts module...\n");
/**
* Request the GPIO lines for the IRQ channels.
*/
retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);
if (retval) {
printk (KERN_ERR "HI: Error: Failed to request GPIO pin#%i for IRQ (error %i)\n", PIN_A_GPIO, retval);
// return -retval;
}
irq = gpio_to_irq (PIN_A_GPIO);
if (irq < 0) {
printk (KERN_ERR "HI: ERROR: Failed to obtain IRQ number for GPIO #%i (error %i)\n", PIN_A_GPIO, irq);
// return -irq;
}
retval = request_irq (irq, irq_handler_pin_a, 0 /*IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING*/, PIN_A_LABEL, NULL);
irq_set_irq_type (irq, IRQ_TYPE_EDGE_BOTH);
if (retval) {
printk (KERN_ERR "HI: ERROR: The requested IRQ line#%i from GPIO#%i (error %i)\n", irq, PIN_A_GPIO, retval);
// return -retval;
}
else {
printk (KERN_INFO "HI: Initialized GPIO #%i to IRQ #%i\n", PIN_A_GPIO, irq);
}
/*
Enable GPIO2 clock
*/
cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
if(!cm_per) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for CM_PER.\n");
return 0;
}
iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
iounmap(cm_per);
/**
* Setup the IRQ registers with the appropriate values.
*/
mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
if(!mem) {
printk (KERN_ERR "HI: ERROR: Failed to remap memory for GPIO Bank 2 IRQ pin configuration.\n");
return 0;
}
// Enable the IRQ ability for GPIO_66.
regval = ioread32 (mem + GPIO_IRQSTATUS_0);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_0);
regval = ioread32 (mem + GPIO_IRQSTATUS_1);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_IRQSTATUS_1);
// Set GPIO_66 for rising and falling edge detection.
regval = ioread32 (mem + GPIO_RISINGDETECT);
regval |= (1 << 2);
iowrite32(regval, mem + GPIO_RISINGDETECT);
regval = ioread32 (mem + GPIO_FALLINGDETECT);
regval |= (1 << 2);
iowrite32 (regval, mem + GPIO_FALLINGDETECT);
// Release the mapped memory.
iounmap (mem);
return 0;
}
static void __exit hello_interrupts_end(void) {
printk ("HI: Releasing IRQ resources...\n");
free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
gpio_free (PIN_A_GPIO);
printk (KERN_INFO "Goodbye hello_interrupts!\n");
}
module_init (hello_interrupts_start);
module_exit (hello_interrupts_end);