I'm trying to increase/decrease backlight value on an embedded linux (yocto) with a button connected to a gpio
I worked step by step, so, first of all, I added a kernel module which generates an interruption each time the button is pressed, it's work like a charm (printk each time the button is pressed, the value is also accessible in userspace at /sys/class/gpio/gpio133/value)
The backlight value is configurable in userspace at /sys/class/backlight/backlight/brightness. I configured the device tree to have 8 different levels of luminosity with the value 0 as the maximum, this also works
Then i tried to get the backlight value in my kernel module by adding a gpio_request and gpio_get_value but it always returns the value : 0. I think the kernel module can't access the gpio because it's already in use by the driver in charge of the backlight, am I right ?
As the gpio and backlight's values are accessible in userspace, i wrote a shell script with an infinite loop which read the gpio state, and if it change I get the backlight value and decrease it. It work's but it used more than 10% of the cpu. I also have a running Qt application with sound, and when the script is running the sound is crackling. So i added a sleep in it to slow down the reading of the gpio state with a duration just enough to avoid crackling sound, but now, sometimes, button presses are missed due the sleep.
Here is the working kernel module without without any attempt to control the backlight:
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Button test management");
MODULE_VERSION("0.1");
static unsigned int GPIO_BUTTON_LUM_PLUS = 133;
static unsigned int irqNumber;
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);
static int __init ebbgpio_init (void)
{
int result=0;
printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n");
if (!gpio_is_valid(GPIO_BUTTON_LUM_PLUS))
{
printk(KERN_INFO "GPIO_TEST: invalid Button GPIO LKM\n");
return -ENODEV;
}
gpio_request(GPIO_BUTTON_LUM_PLUS, "sysfs");
gpio_direction_input(GPIO_BUTTON_LUM_PLUS);
gpio_set_debounce(GPIO_BUTTON_LUM_PLUS, 200);
gpio_export(GPIO_BUTTON_LUM_PLUS, false);
printk(KERN_INFO "GPIO_TEST: the button state is currently: %d\n", gpio_get_value(GPIO_BUTTON_LUM_PLUS));
irqNumber = gpio_to_irq(GPIO_BUTTON_LUM_PLUS);
printk(KERN_INFO "GPIO_TEST: the button is mapped to IRQ: %d\n", irqNumber);
result = request_irq(irqNumber, (irq_handler_t) ebbgpio_irq_handler, IRQF_TRIGGER_RISING, "ebb_gpio_handler", NULL);
printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result);
return result;
}
static void __exit ebbgpio_exit(void)
{
printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(GPIO_BUTTON_LUM_PLUS));
gpio_unexport(GPIO_BUTTON_LUM_PLUS);
free_irq(irqNumber, NULL);
gpio_free(GPIO_BUTTON_LUM_PLUS);
}
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs)
{
printk(KERN_INFO "GPIO_TEST: Interrupt! (button state is %d)\n", gpio_get_value(GPIO_BUTTON_LUM_PLUS));
return (irq_handler_t) IRQ_HANDLED;
}
module_init(ebbgpio_init);
module_exit(ebbgpio_exit);
In the future I will need to read 2 gpio,one for decrease backlight value and the other one to increase the value, so i'm searching for a better solution Any help would be appreciate