GPIO debounce on IMX8MP

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

GPIO debounce on IMX8MP

1,165 Views
growbook
Contributor I

Hello,

I'm trying to set GPIO debounce time on Linux made from Yocto.

I was going to do it using gpio_set_debounce() function.

Like this :

if(gpio_set_debounce(GPIO_25_IN, 200) < 0){

pr_err("ERROR: gpio_set_debounce - %d\n", GPIO_25_IN);
}
 

 

However, it always makes an error.

Is it possible to enable GPIO debounce? or Is there any pre-defined debounce time?

 

regards

growbook

 

0 Kudos
Reply
3 Replies

1,120 Views
Dhruvit
NXP TechSupport
NXP TechSupport

Hi @growbook,

I hope you are doing well.

Please share the dmesg logs or error logs also to debug the issue further.

Thanks & Regards,
Dhruvit Vasavada

0 Kudos
Reply

1,107 Views
growbook
Contributor I

Sorry that I've offered a few clues for debugging.

This is my code.

(You may not need to read the whole code. I'll explain it in the next paragraph)

/***************************************************************************//**
*  \file       driver.c
*
*  \details    Simple GPIO driver explanation (GPIO Interrupt)
*
*  \author     EmbeTronicX
*
*  \Tested with Linux raspberrypi 5.4.51-v7l+
*
*******************************************************************************/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/uaccess.h>  //copy_to/from_user()
#include <linux/gpio.h>     //GPIO
#include <linux/interrupt.h>
#include <linux/err.h>
/* Since debounce is not supported in Raspberry pi, I have addded this to disable 
** the false detection (multiple IRQ trigger for one interrupt).
** Many other hardware supports GPIO debounce, I don't want care about this even 
** if this has any overhead. Our intention is to explain the GPIO interrupt.
** If you want to disable this extra coding, you can comment the below macro.
** This has been taken from : https://raspberrypi.stackexchange.com/questions/8544/gpio-interrupt-debounce
**
** If you want to use Hardaware Debounce, then comment this EN_DEBOUNCE.
**
*/
// #define EN_DEBOUNCE
#ifdef EN_DEBOUNCE
#include <linux/jiffies.h>
extern unsigned long volatile jiffies;
unsigned long old_jiffie = 0;
#endif
//LED is connected to this GPIO
#define GPIO_137_OUT 137
//LED is connected to this GPIO
#define GPIO_135_IN  135
//GPIO_135_IN value toggle
unsigned int led_toggle = 0; 
//This used for storing the IRQ number for the GPIO
unsigned int GPIO_irqNumber;
//Interrupt handler for GPIO 135. This will be called whenever there is a raising edge detected. 
static irqreturn_t gpio_irq_handler(int irq,void *dev_id) 
{
  static unsigned long flags = 0;
#ifdef EN_DEBOUNCE
   unsigned long diff = jiffies - old_jiffie;
   pr_info("diff calculation is called");
   if (diff < 20)
   {
     return IRQ_HANDLED;
   }
  
  old_jiffie = jiffies;
#endif  
  local_irq_save(flags);
  led_toggle = (0x01 ^ led_toggle);                             // toggle the old value
  gpio_set_value(GPIO_137_OUT, led_toggle);                      // toggle the GPIO_137_OUT
  pr_info("Interrupt Occurred : GPIO_137_OUT : %d ",gpio_get_value(GPIO_137_OUT));
  local_irq_restore(flags);
  return IRQ_HANDLED;
}
 
dev_t dev = 0;
static struct class *dev_class;
static struct cdev etx_cdev;
 
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
 
 
/*************** Driver functions **********************/
static int etx_open(struct inode *inode, struct file *file);
static int etx_release(struct inode *inode, struct file *file);
static ssize_t etx_read(struct file *filp, 
                char __user *buf, size_t len,loff_t * off);
static ssize_t etx_write(struct file *filp, 
                const char *buf, size_t len, loff_t * off);
/******************************************************/
//File operation structure 
static struct file_operations fops =
{
  .owner          = THIS_MODULE,
  .read           = etx_read,
  .write          = etx_write,
  .open           = etx_open,
  .release        = etx_release,
};
/*
** This function will be called when we open the Device file
*/ 
static int etx_open(struct inode *inode, struct file *file)
{
  pr_info("Device File Opened...!!!\n");
  return 0;
}
/*
** This function will be called when we close the Device file
*/ 
static int etx_release(struct inode *inode, struct file *file)
{
  pr_info("Device File Closed...!!!\n");
  return 0;
}
/*
** This function will be called when we read the Device file
*/ 
static ssize_t etx_read(struct file *filp, 
                char __user *buf, size_t len, loff_t *off)
{
  uint8_t gpio_state = 0;
  
  //reading GPIO value
  gpio_state = gpio_get_value(GPIO_137_OUT);
  
  //write to user
  len = 1;
  if( copy_to_user(buf, &gpio_state, len) > 0) {
    pr_err("ERROR: Not all the bytes have been copied to user\n");
  }
  
  pr_info("Read function : GPIO_137 = %d \n", gpio_state);
  pr_info("Read function : GPIO_135 = %d \n", gpio_get_value(GPIO_135_IN));
  
  return 0;
}
/*
** This function will be called when we write the Device file
*/
static ssize_t etx_write(struct file *filp, 
                const char __user *buf, size_t len, loff_t *off)
{
  uint8_t rec_buf[10] = {0};
  
  if( copy_from_user( rec_buf, buf, len ) > 0) {
    pr_err("ERROR: Not all the bytes have been copied from user\n");
  }
  

  if (rec_buf[0]=='1') {
    //set the GPIO value to HIGH
    gpio_set_value(GPIO_137_OUT, 1);
  } else if (rec_buf[0]=='0') {
    //set the GPIO value to LOW
    gpio_set_value(GPIO_137_OUT, 0);
  } else {
    pr_err("Unknown command : Please provide either 1 or 0 \n");
  }

  pr_info("Write Function : GPIO_137 Set = %c\n", rec_buf[0]);
  
  return len;
}
/*
** Module Init function
*/ 
static int __init etx_driver_init(void)
{
  /*Allocating Major number*/
  if((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) <0){
    pr_err("Cannot allocate major number\n");
    goto r_unreg;
  }
  pr_info("Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
  /*Creating cdev structure*/
  cdev_init(&etx_cdev,&fops);
  /*Adding character device to the system*/
  if((cdev_add(&etx_cdev,dev,1)) < 0){
    pr_err("Cannot add the device to the system\n");
    goto r_del;
  }
  /*Creating struct class*/
  if(IS_ERR(dev_class = class_create(THIS_MODULE,"etx_class"))){
    pr_err("Cannot create the struct class\n");
    goto r_class;
  }
  /*Creating device*/
  if(IS_ERR(device_create(dev_class,NULL,dev,NULL,"etx_device"))){
    pr_err( "Cannot create the Device \n");
    goto r_device;
  }
  
  //Output GPIO configuration
  //Checking the GPIO is valid or not
  if(gpio_is_valid(GPIO_137_OUT) == false){
    pr_err("GPIO %d is not valid\n", GPIO_137_OUT);
    goto r_device;
  }
  
  //Requesting the GPIO
  if(gpio_request(GPIO_137_OUT,"GPIO_137_OUT") < 0){
    pr_err("ERROR: GPIO %d request\n", GPIO_137_OUT);
    goto r_gpio_out;
  }
  
  //configure the GPIO as output
  gpio_direction_output(GPIO_137_OUT, 0);
  
  //Input GPIO configuratioin
  //Checking the GPIO is valid or not
  if(gpio_is_valid(GPIO_135_IN) == false){
    pr_err("GPIO %d is not valid\n", GPIO_135_IN);
    goto r_gpio_in;
  }
  
  //Requesting the GPIO
  if(gpio_request(GPIO_135_IN,"GPIO_135_IN") < 0){
    pr_err("ERROR: GPIO %d request\n", GPIO_135_IN);
    goto r_gpio_in;
  }
  
  //configure the GPIO as input
  gpio_direction_input(GPIO_135_IN);
  
  /*
  ** I have commented the below few lines, as gpio_set_debounce is not supported 
  ** in the Raspberry pi. So we are using EN_DEBOUNCE to handle this in this driver.
  */ 
#ifndef EN_DEBOUNCE
  //Debounce the button with a delay of 200ms
  pr_info("gpio_set_debounce is called\n");
  if(gpio_set_debounce(GPIO_135_IN, 1000) < 0){
    pr_err("ERROR: gpio_set_debounce - %d\n", GPIO_135_IN);
    //goto r_gpio_in;
  }
#endif
  
  //Get the IRQ number for our GPIO
  GPIO_irqNumber = gpio_to_irq(GPIO_135_IN);
  pr_info("GPIO_irqNumber = %d\n", GPIO_irqNumber);
  
  if (request_irq(GPIO_irqNumber,             //IRQ number
                  (void *)gpio_irq_handler,   //IRQ handler
                  IRQF_TRIGGER_RISING,        //Handler will be called in raising edge
                  "etx_device",               //used to identify the device name using this IRQ
                  NULL)) {                    //device id for shared IRQ
    pr_err("my_device: cannot register IRQ ");
    goto r_gpio_in;
  }
  
  
 
  pr_info("Device Driver Insert...Done!!!\n");
  return 0;
r_gpio_in:
  gpio_free(GPIO_135_IN);
r_gpio_out:
  gpio_free(GPIO_137_OUT);
r_device:
  device_destroy(dev_class,dev);
r_class:
  class_destroy(dev_class);
r_del:
  cdev_del(&etx_cdev);
r_unreg:
  unregister_chrdev_region(dev,1);
  
  return -1;
}
/*
** Module exit function
*/
static void __exit etx_driver_exit(void)
{
  free_irq(GPIO_irqNumber,NULL);
  gpio_free(GPIO_135_IN);
  gpio_free(GPIO_137_OUT);
  device_destroy(dev_class,dev);
  class_destroy(dev_class);
  cdev_del(&etx_cdev);
  unregister_chrdev_region(dev, 1);
  pr_info("Device Driver Remove...Done!!\n");
}
 
module_init(etx_driver_init);
module_exit(etx_driver_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("EmbeTronicX <embetronicx@gmail.com>");
MODULE_DESCRIPTION("A simple device driver - GPIO Driver (GPIO Interrupt) ");
MODULE_VERSION("1.33");

This code is a simple GPIO driver for handling interrupts on a Linux system. Although comments in the code seem like targeting the Raspberry Pi platform, I've tested it on Imx8mp board. It allows users to control an output GPIO (GPIO_137) and receive interrupt notifications when a rising edge is detected on an input GPIO (GPIO_135).

The functionality I want to implement is setting debounce time. I've tried to search 'debounce' on every datasheet of imx8mp, but I could not find it. So, I was wondering that Imx8mp support debounce time or not.

 

Also, Here is dmesg.

[  124.721829] gpio_irq: loading out-of-tree module taints kernel.
[  124.728804] Major = 510 Minor = 0
[  124.732897] gpio_set_debounce is called
[  124.736778] ERROR: gpio_set_debounce - 135
[  124.740951] GPIO_irqNumber = 224
[  124.744225] Device Driver Insert...Done!!!

This is a message when the device driver module started.

At the fourth line, gpio_set_debounce returns an error.

 

So, now I'm trying to set the debounce time at device tree like this.

 gpio-keys {
                compatible = "gpio-keys";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_switch>;

                switch {
                        label = "button";
                        gpios = <&gpio5 7  GPIO_ACTIVE_HIGH>;
                        debounce-interval = <100>;
                };
        };

(emitted)


pinctrl_gpio_switch: gpioswitchgrp {
                fsl,pins = <
                        MX8MP_IOMUXC_ECSPI1_MOSI__GPIO5_IO07    0x16
                >;
        };

And it also doesn't work as I expected.

Thank you for your reply.

 

Best regards,

growbook91

0 Kudos
Reply

1,086 Views
Dhruvit
NXP TechSupport
NXP TechSupport

Hi @growbook,

I hope you are doing well.

->Thanks for sharing the code & further details.

->Please check with the pad settings you made in the code are being used by other nodes or not in the same device tree.
->I found out that uart3 also uses the same pad so please disable the uart3 node from the device tree by doing the below settings.
status = "disabled"

Now it should work.

Thanks & Regards,
Dhruvit Vasavada

0 Kudos
Reply