Article Directory
1 Linux comes with the source code of the button driver
The button driver is also integrated in the Linux kernel. If you want to use it, you need to configure it in the kernel. Find the corresponding configuration according to the following path:
Device Drivers --->
Input device support --->
[*] Keyboards --->
<*> GPIO Buttons
Select the "GPIO Buttons" option, and the driver will be compiled into the Linux kernel, as shown in Figure 1.1:
After saving and exiting, "CONFIG_KEYBOARD_GPIO=y" will appear under the .congfig file.
The key driver path in the Linux kernel is drivers/input/keyboard/gpio_keys.c. The key driver is based on the platform framework and uses the input subsystem to implement functions.
Part of the code in the gpio_keys.c file is as follows:
673 static const struct of_device_id gpio_keys_of_match[] = {
674 {
.compatible = "gpio-keys", },
675 {
},
676 };
......
842 static struct platform_driver gpio_keys_device_driver = {
843 .probe = gpio_keys_probe,
844 .remove = gpio_keys_remove,
845 .driver = {
846 .name = "gpio-keys",
847 .pm = &gpio_keys_pm_ops,
848 .of_match_table = of_match_ptr(gpio_keys_of_match),
849 }
850 };
851
852 static int __init gpio_keys_init(void)
853 {
854 return platform_driver_register(&gpio_keys_device_driver);
855 }
856
857 static void __exit gpio_keys_exit(void)
858 {
859 platform_driver_unregister(&gpio_keys_device_driver);
860 }
As can be seen from the above code, this is a typical platform frame structure. When the device is successfully matched, the gpio_keys_probe function will be executed. Let’s see what is implemented in the gpio_keys_probe function:
689 static int gpio_keys_probe(struct platform_device *pdev)
690 {
691 struct device *dev = &pdev->dev;
692 const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
693 struct gpio_keys_drvdata *ddata;
694 struct input_dev *input;
695 size_t size;
696 int i, error;
697 int wakeup = 0;
698
699 if (!pdata) {
700 pdata = gpio_keys_get_devtree_pdata(dev);
701 if (IS_ERR(pdata))
702 return PTR_ERR(pdata);
703 }
......
713 input = devm_input_allocate_device(dev);
714 if (!input) {
715 dev_err(dev, "failed to allocate input device\n");
716 return -ENOMEM;
717 }
718
719 ddata->pdata = pdata;
720 ddata->input = input;
721 mutex_init(&ddata->disable_lock);
722
723 platform_set_drvdata(pdev, ddata);
724 input_set_drvdata(input, ddata);
725
726 input->name = pdata->name ? : pdev->name;
727 input->phys = "gpio-keys/input0";
728 input->dev.parent = &pdev->dev;
729 input->open = gpio_keys_open;
730 input->close = gpio_keys_close;
731
732 input->id.bustype = BUS_HOST;
733 input->id.vendor = 0x0001;
734 input->id.product = 0x0001;
735 input->id.version = 0x0100;
736
737 /* Enable auto repeat feature of Linux input subsystem */
738 if (pdata->rep)
739 __set_bit(EV_REP, input->evbit);
740
741 for (i = 0; i < pdata->nbuttons; i++) {
742 const struct gpio_keys_button *button = &pdata->buttons[i];
743 struct gpio_button_data *bdata = &ddata->data[i];
744
745 error = gpio_keys_setup_key(pdev, input, bdata, button);
746 if (error)
747 return error;
748
749 if (button->wakeup)
750 wakeup = 1;
751 }
......
760 error = input_register_device(input);
761 if (error) {
762 dev_err(dev, "Unable to register input device, error: %d\n",
763 error);
764 goto err_remove_group;
765 }
......
774 }
In line 700, call the gpio_keys_get_devtree_pdata function to get the KEY related device node information from the device tree.
On line 713, use the devm_input_allocate_device function to apply for input_dev.
726~735, initialize input_dev.
Line 739, set the input_dev event, here is the EV_REP event.
On line 745, call the gpio_keys_setup_key function to continue setting the KEY. This function will set the EV_KEY event code of input_dev (that is, which key is simulated by KEY).
On line 760, call the input_register_device function to register input_dev with the Linux system.
Let's look at the content of the gpio_keys_setup_key function again:
437 static int gpio_keys_setup_key(struct platform_device *pdev,
438 struct input_dev *input,
439 struct gpio_button_data *bdata,
440 const struct gpio_keys_button *button)
441 {
442 const char *desc = button->desc ? button->desc : "gpio_keys";
443 struct device *dev = &pdev->dev;
444 irq_handler_t isr;
445 unsigned long irqflags;
446 int irq;
447 int error;
448
449 bdata->input = input;
450 bdata->button = button;
451 spin_lock_init(&bdata->lock);
452
453 if (gpio_is_valid(button->gpio)) {
454
455 error = devm_gpio_request_one(&pdev->dev, button->gpio,
456 GPIOF_IN, desc);
457 if (error < 0) {
458 dev_err(dev, "Failed to request GPIO %d, error %d\n",
459 button->gpio, error);
460 return error;
......
488 isr = gpio_keys_gpio_isr;
489 irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
490
491 } else {
492 if (!button->irq) {
493 dev_err(dev, "No IRQ specified\n");
494 return -EINVAL;
495 }
496 bdata->irq = button->irq;
......
506
507 isr = gpio_keys_irq_isr;
508 irqflags = 0;
509 }
510
511 input_set_capability(input, button->type ?: EV_KEY, button->code);
......
540 return 0;
541 }
In line 511, call the input_set_capability function to set the EV_KEY event and the key type of KEY, that is, which key is KEY used as? We will set the specified KEY as which button in the device tree.
After everything is ready, all that is left is to wait for the button to be pressed, and then report the event to the Linux kernel. The event report is done in the gpio_keys_irq_isr function. The content of this function is as follows:
392 static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
393 {
394 struct gpio_button_data *bdata = dev_id;
395 const struct gpio_keys_button *button = bdata->button;
396 struct input_dev *input = bdata->input;
397 unsigned long flags;
398
399 BUG_ON(irq != bdata->irq);
400
401 spin_lock_irqsave(&bdata->lock, flags);
402
403 if (!bdata->key_pressed) {
404 if (bdata->button->wakeup)
405 pm_wakeup_event(bdata->input->dev.parent, 0);
406
407 input_event(input, EV_KEY, button->code, 1);
408 input_sync(input);
409
410 if (!bdata->release_delay) {
411 input_event(input, EV_KEY, button->code, 0);
412 input_sync(input);
413 goto out;
414 }
415
416 bdata->key_pressed = true;
417 }
418
419 if (bdata->release_delay)
420 mod_timer(&bdata->release_timer,
421 jiffies + msecs_to_jiffies(bdata->release_delay));
422 out:
423 spin_unlock_irqrestore(&bdata->lock, flags);
424 return IRQ_HANDLED;
425 }
It can be seen that the key_input.c driver file we wrote before is the same as the driver file that comes with the Linux kernel. They both apply and initialize the input_dev structure, set events, and then register with the Linux kernel. Finally, the event and event value are reported in the key interrupt processing function.
2 The use of the Linux kernel's own button driver
It is also very simple to use the built-in button driver in the Linux kernel, just add the specified device node in the device tree. For details, please refer to the Documentation/devicetree/bindings/input/gpio-keys.txt file.
There are several requirements for node content:
① The node name is "gpio-keys".
② The compatible attribute value of the gpio-keys node must be set to "gpio-keys".
③ All KEYs are child nodes of gpio-keys, and each child node can describe itself with the following attributes:
gpios: GPIO information connected to KEY.
interrupts: The GPIO interrupt information used by KEY is not necessary and can be omitted.
label: KEY name
linux, code: KEY keys to be simulated, that is, these keys in sample code 58.1.2.4.
④ Add autorepeat if the key supports double pressing.
Open the topeet_emmc_4_3.dts file, according to the above requirements, create the device node of the button, the content is as follows:
1 gpio-keys {
2 compatible = "gpio-keys";
3 #address-cells = <1>;
4 #size-cells = <0>;
5 autorepeat;
6 key0 {
7 label = "GPIO Key Enter";
8 linux,code = <KEY_ENTER>;
9 gpios = <&gpio1 18 GPIO_ACTIVE_LOW>;
10 };
11 };
In line 2, the value of the compatible attribute must be the same as the compatible name in the driver.
In line 5, autorepeat indicates support for key presses.
Line 6~10, set the button information, set the button label name. Line 8, set the function of the button, set the button to the KEY_ENTER function, which is the enter key. Finally, the 9th line sets the GPIO pin used by the button.
After adding the device node of the button in the device tree, recompile the device tree file, then download the device tree file again, start the Linux system, and check the /dev/input directory, as shown in Figure 2.1:
You can see that the event1 file has been generated. This file is the device file corresponding to the button KEY0. Use the hexdump command to view the /dev/input/event1 file. The command is as follows:
hexdump /dev/input/event1
Then press the button KEY0 on the development board, and the terminal will show the following content:
The output of the terminal indicates that the key driver in the Linux kernel is working normally. If the terminal does not output, and there is no response to the key press, there can be the following reasons:
① Whether to enable the Linux kernel KEY driver.
② Whether the gpio-keys node in the device tree is successfully created.
③ Whether there are other peripherals in the device tree that also use the GPIO corresponding to the KEY button, but we have not deleted these peripheral information.