BeagleBone Black interrupts kernel driver

I am trying to work with interrupts but I am getting the following error due to ioread32.

As I saw in chapter "25.3.3 Interrupt Functions" in "AM335x SitaraTM Processors - Technical Reference Manual"

To generate an interrupt request to the main processor for a specific event (level or logic transition) that occurs on the GPIO pin, the GPIO configuration registers must be programmed as follows:

β€’ Interrupts for the GPIO channel must be included in the GPIO_IRQSTATUS_SET_0 and / or GPIO_IRQSTATUS_SET_1 registers.

β€’ Pending events on the GPIO input to trigger an interrupt request must 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 to

+3


source to share


2 answers


The problem was that the clock of the GPIO2 module was disabled.

"8.1.12.1.30 CM_PER_GPIO2_CLKCTRL Register (offset = B0h) [reset = 30000h]" from "AM335x SitaraTM Processors - Technical Reference Manual"



Bits 1: 0: Control how compulsory hours are controlled. 0x0 = DISABLED: module is disabled via SW. Any OCP access to the module will result in an error, except when caused by waking the module (asynchronous wakeup). 0x1 = RESERVED_1: reserved 0x2 = ENABLE: module is explicitly enabled. The interface clock (if not used for functions) can be set according to the clock domain state. Functional clocks ensure presence remains. Until, in this configuration, a domain ownership sleep transition cannot occur. 0x3 = DONE: Reserved

+3


source


In order for the above code to work, the GPIO2 clock must be activated using the CM_PER_GPIO2_CLKCTRL register and the GPIO pin must be selected from GPIO2. The above code used GPIO 36, which is on GPIO1 (and is used by the internal flash anyway). The following code turns on the GPIO2 clock and uses GPIO 68 (which is on the P9 header, 10 bits):



#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);

      

0


source







All Articles