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){
However, it always makes an error.
Is it possible to enable GPIO debounce? or Is there any pre-defined debounce time?
regards
growbook
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
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
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