[Beijing Xunwei] i.MX6ULL Terminator Linux INPUT subsystem experiment Linux comes with button driver

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:
Insert picture description here

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:
Insert picture description here

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:
Insert picture description here

Figure 2.2

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.

Insert picture description here

Guess you like

Origin blog.csdn.net/BeiJingXunWei/article/details/112258428