I am a newbie trying to write a simple GPIO driver that generates an interrupt when push button 1 or 2 is pressed. The code has just an init and exit function for now.
when I try to load the driver, I see the failure log as shown below:
Also, is there any macro to map the physical address to the virtual address for the IO registers? From the log it appears that the physical address is being used as the virtual address.
Thanks
svv
----------------------------------------------
/ $ insmod ./gpio_test.ko
Init'ing Button GPIO
Bank1: Direction Ctrl addr 0xe000a244
Unable to handle kernel paging request at virtual address e000a244
pgd = ddfec000
[e000a244] *pgd=00000000
Internal error: Oops: 5 [#1] PREEMPT SMP ARM
Modules linked in: gpio_test(+)
CPU: 1 Not tainted (3.6.0-xilinx-dirty #1)
PC is at gpio_but_init+0x14/0x9c [gpio_test]
LR is at gpio_but_init+0x10/0x9c [gpio_test]
pc : [<bf00002c>] lr : [<bf000028>] psr: 60000013
sp : dd40dec0 ip : dd40c010 fp : 00000000
r10: 00000320 r9 : 00000014 r8 : 00000001
r7 : df443200 r6 : 00000000 r5 : bf000018 r4 : e000a000
r3 : c052bbc4 r2 : c052bbc4 r1 : 00000001 r0 : bf000167
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 18c5387d Table: 1dfec04a DAC: 00000015
Process insmod (pid: 625, stack limit = 0xdd40c2f0)
Stack: (0xdd40dec0 to 0xdd40e000)
dec0: bf000018 c0554840 dd40ded0 c00085ac c052d6a4 00000001 bf000244 bf000244
dee0: bf00028c bf000244 bf00028c 00000001 df443200 00000001 00000014 c005c768
df00: bf000250 00007fff c01ae208 c00083e8 000000f7 c039293c e0866000 000e9f01
df20: 000002f8 0000002d e0866000 00000f09 e0866718 e086664f e0866df0 00000394
df40: 00000454 00000000 00000000 00000012 00000013 0000000a 00000008 00000006
df60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 c04a0eb8
df80: 00000001 000f31b4 beca3eb4 00000069 00000080 c000e1e4 dd40c000 00000000
dfa0: 00000001 c000e080 000f31b4 beca3eb4 000f6040 00000f09 000e9f01 00000000
dfc0: 000f31b4 beca3eb4 00000069 00000080 beca3eb8 00000001 beca3eb8 00000001
dfe0: 00000001 beca3b6c 0002f1dc b6edebd4 60000010 000f6040 0000003e 00000000
[<bf00002c>] (gpio_but_init+0x14/0x9c [gpio_test]) from [<c00085ac>] (do_one_initcall+0x90/0x160)
[<c00085ac>] (do_one_initcall+0x90/0x160) from [<c005c768>] (sys_init_module+0x17e4/0x19d0)
[<c005c768>] (sys_init_module+0x17e4/0x19d0) from [<c000e080>] (ret_fast_syscall+0x0/0x30)
Code: e59f4074 e59f0074 eb4e1b93 e59f0070 (e5942244)
---[ end trace ad007467df7330b4 ]---
Segmentation fault
/ $
/* ****** C code for the driver ********/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/sysctl.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/io.h>
MODULE_LICENSE("Dual BSD/GPL");
#ifndef uint32_t
typedef unsigned int uint32_t;
#endif
#define gpio_readl(offset)tt __raw_readl(offset)
#define gpio_writel(val, offset)t__raw_writel(val, offset)
#define GPIO_INTR_ID 52 /* Sec 7.2.3 of Ref. Manual */
#define GPIO_BASE_ADDRESS 0xE000A000
#define GPIO_CONFIG_OFFSET (GPIO_BASE_ADDRESS + 0x204)
#define GPIO_CONFIG_SIZE (0x40)
#define GPIO_CONFIG_ADDR(bank) (GPIO_CONFIG_OFFSET + (bank * GPIO_CONFIG_SIZE))
#define BUTTON_MASK 0x00030000
typedef struct _gpioConfig_
{
tuint32_t nDirectionCtrl;
tuint32_t nOutputEnable;
tuint32_t nInterruptMaskStatus;
tuint32_t nInterruptEnable;
tuint32_t nInterruptDisable;
tuint32_t nInterruptStatus;
tuint32_t nInterruptType;
tuint32_t nInterruptPolarity;
tuint32_t nInterruptAnyEdge;
} GpioConfig_s;
/** PB1 --> GPIO Bank 1 / 18
* PB2 --> GPIO Bank 1 / 19
*/
static int device_file_major_number = 0;
static const char device_name[] = "test_gpio";
static irqreturn_t gpio_irq_handler(int irq, void *data)
{
tprintk( KERN_NOTICE "svv_gpio: Interrupt routine called
");
treturn IRQ_HANDLED;
}
static int gpio_but_init(void)
{
volatile GpioConfig_s *ptr = (GpioConfig_s *)(GPIO_CONFIG_ADDR(1));
uint32_t nData;
printk(KERN_ALERT "Init'ing Button GPIO
");
printk(KERN_ALERT "Bank1: Direction Ctrl addr 0x%x
", (GPIO_CONFIG_ADDR(1) + offsetof(GpioConfig_s, nDirectionCtrl)) );
/* Set MIO 18/19 to inputs */
nData = gpio_readl(GPIO_CONFIG_ADDR(1) + offsetof(GpioConfig_s, nDirectionCtrl));
nData &= (~BUTTON_MASK);
gpio_writel(nData, GPIO_CONFIG_ADDR(1) + offsetof(GpioConfig_s, nDirectionCtrl));
ptr->nDirectionCtrl = nData;
printk(KERN_ALERT "Bank1: Direction Ctrl 0x%x
", nData);
/**
* remaining code
* */
request_irq(GPIO_INTR_ID, /* The number of the gpio IRQ == 52 */
gpio_irq_handler, /* our handler */
IRQF_SHARED,
"gpio IRQ handler", NULL);
return 0;
}
static void gpio_but_exit(void)
{
t/* ***
t * exit code
t * */
}
module_init(gpio_but_init);
module_exit(gpio_but_exit);