Files
gpio-keyboard-driver/gpio-keyboard-driver.c
2026-02-07 01:40:13 -06:00

129 lines
3.1 KiB
C

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/platform_device.h>
static struct input_dev *kbd_dev;
static int gpio_num;
static int irq_num;
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
int state = gpio_get_value(gpio_num);
/* Active low button */
if (state == 0) {
input_report_key(kbd_dev, KEY_A, 1);
input_sync(kbd_dev);
} else {
input_report_key(kbd_dev, KEY_A, 0);
input_sync(kbd_dev);
}
return IRQ_HANDLED;
}
static int gpio_kbd_probe(struct platform_device *pdev)
{
int ret;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
if (!np)
return -EINVAL;
/* Read GPIO from DT */
gpio_num = of_get_named_gpio(np, "gpios", 0);
if (gpio_num < 0) {
dev_err(dev, "Failed to get GPIO from DT\n");
return gpio_num;
}
ret = gpio_request(gpio_num, "gpio_kbd_button");
if (ret) {
dev_err(dev, "Failed to request GPIO\n");
return ret;
}
gpio_direction_input(gpio_num);
/* Allocate input device */
kbd_dev = input_allocate_device();
if (!kbd_dev) {
dev_err(dev, "Failed to allocate input device\n");
gpio_free(gpio_num);
return -ENOMEM;
}
kbd_dev->name = "GPIO Keyboard Device";
kbd_dev->evbit[0] = BIT_MASK(EV_KEY);
set_bit(KEY_A, kbd_dev->keybit);
ret = input_register_device(kbd_dev);
if (ret) {
dev_err(dev, "Failed to register input device\n");
input_free_device(kbd_dev);
gpio_free(gpio_num);
return ret;
}
/* Get IRQ from DT */
irq_num = of_irq_get(np, 0);
if (irq_num < 0) {
dev_err(dev, "Failed to get IRQ from DT\n");
input_unregister_device(kbd_dev);
gpio_free(gpio_num);
return irq_num;
}
ret = request_irq(irq_num,
gpio_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"gpio_kbd_irq",
NULL);
if (ret) {
dev_err(dev, "Failed to request IRQ\n");
input_unregister_device(kbd_dev);
gpio_free(gpio_num);
return ret;
}
dev_info(dev, "GPIO keyboard driver loaded\n");
return 0;
}
static void gpio_kbd_remove(struct platform_device *pdev)
{
free_irq(irq_num, NULL);
input_unregister_device(kbd_dev);
gpio_free(gpio_num);
}
static const struct of_device_id gpio_kbd_of_match[] = {
{ .compatible = "arcade,gpio-keyboard" },
{ }
};
MODULE_DEVICE_TABLE(of, gpio_kbd_of_match);
static struct platform_driver gpio_kbd_driver = {
.probe = gpio_kbd_probe,
.remove = gpio_kbd_remove,
.driver = {
.name = "gpio-keyboard",
.of_match_table = gpio_kbd_of_match,
},
};
module_platform_driver(gpio_kbd_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Nicholas Mello");
MODULE_DESCRIPTION("GPIO-based virtual keyboard driver using Device Tree");