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