16 内核里gpio-keys设备驱动的设备树描述

此设备驱动适用于连接到一个具有中断功能的io口的按键驱动.
使用platform_device方法可参考:http://blog.csdn.net/jklinux/article/details/73828786

此设备驱动在内核里配置:

make menuconfig ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-

  Device Drivers  ---> 
     Input device support  ---> 
        [*]   Keyboards  ---> 
           <*>   GPIO Buttons

驱动源码在: drivers/input/keyboard/gpio_keys.c


898 static struct platform_driver gpio_keys_device_driver = {
899     .probe      = gpio_keys_probe,
900     .remove     = gpio_keys_remove,
901     .driver     = {
902         .name   = "gpio-keys",
903         .pm = &gpio_keys_pm_ops,
904         .of_match_table = gpio_keys_of_match,
905     }
906 };

722 static const struct of_device_id gpio_keys_of_match[] = {
723     { .compatible = "gpio-keys", },
724     { },
725 };
726 MODULE_DEVICE_TABLE(of, gpio_keys_of_match);

通过上面两部分内容可以得知,在设备树里设备节点的compatible属性值应为"gpio-keys".

当匹配上时, gpio_keys_probe函数就会被触发调用,获取设备提供的资源.
728 static int gpio_keys_probe(struct platform_device *pdev)
729 {
730     struct device *dev = &pdev->dev;
731     const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
732     struct fwnode_handle *child = NULL;
733     struct gpio_keys_drvdata *ddata;
734     struct input_dev *input;
735     size_t size;
736     int i, error;
737     int wakeup = 0;
738 
739     if (!pdata) {
740         pdata = gpio_keys_get_devtree_pdata(dev); //获取设备树里设备节点提供的资源
741         if (IS_ERR(pdata))
742             return PTR_ERR(pdata);
743     }
744 
745     size = sizeof(struct gpio_keys_drvdata) +
746             pdata->nbuttons * sizeof(struct gpio_button_data);
747     ddata = devm_kzalloc(dev, size, GFP_KERNEL);
748     if (!ddata) {
749         dev_err(dev, "failed to allocate state\n");
750         return -ENOMEM;
751     }
752 
753     ddata->keymap = devm_kcalloc(dev,
754                      pdata->nbuttons, sizeof(ddata->keymap[0]),
755                      GFP_KERNEL);
756     if (!ddata->keymap)
757         return -ENOMEM;
758 
759     input = devm_input_allocate_device(dev);
760     if (!input) {
761         dev_err(dev, "failed to allocate input device\n");
762         return -ENOMEM;
763     }
764 
    ... //初始化input_dev对象的成员
788     if (pdata->rep)
789         __set_bit(EV_REP, input->evbit);
790 
791     for (i = 0; i < pdata->nbuttons; i++) {
792         const struct gpio_keys_button *button = &pdata->buttons[i];
793 
794         if (!dev_get_platdata(dev)) {
795             child = device_get_next_child_node(dev, child); //获取设备节点里的子节点
            ...
803 
804         error = gpio_keys_setup_key(pdev, input, ddata,
805                         button, i, child); //根据子节点提供的属性值设置input_dev对象所支持的键码
        ...
813     }
        ...
824     error = input_register_device(input);
    ...

659 static struct gpio_keys_platform_data *
660 gpio_keys_get_devtree_pdata(struct device *dev)
661 {
662     struct gpio_keys_platform_data *pdata;
663     struct gpio_keys_button *button;
664     struct fwnode_handle *child;
665     int nbuttons;
666     
667     nbuttons = device_get_child_node_count(dev);
668     if (nbuttons == 0)
669         return ERR_PTR(-ENODEV);//意味着需要通过设备节点的子节点来提供资源
        ...
681 
682     pdata->rep = device_property_read_bool(dev, "autorepeat");
683     //表示设备节点可以有一个autorepeat属性,属性值为bool类型(0/1). 用于表示输入设备是否自动间隔地重复提交按键.
684     device_property_read_string(dev, "label", &pdata->name);
685     //表示设备节点可以有一个label属性, 属性性为string类型.用于指定输入设备的名字
686     device_for_each_child_node(dev, child) { //遍历子节点
687         if (is_of_node(child))
688             button->irq =
689                 irq_of_parse_and_map(to_of_node(child), 0);
690 
691         if (fwnode_property_read_u32(child, "linux,code",
692                          &button->code)) {
693             dev_err(dev, "Button without keycode\n");
694             fwnode_handle_put(child);
695             return ERR_PTR(-EINVAL); //意味着每个子节点都必须有"linux,code"属性,属性值为u32类型。用于指定此子节点对应的按键的键码.
696         }
697 
698         fwnode_property_read_string(child, "label", &button->desc);
699         //每个子节点还可以有一个label属性,属性值为string类型
700         if (fwnode_property_read_u32(child, "linux,input-type",
701                          &button->type))
702             button->type = EV_KEY; //每个字节点还可以通过"linux,input-type"属性来指定输入设备所支持的事件类型.  如果不提供则设置为EV_KEY
703 
704         button->wakeup =
705             fwnode_property_read_bool(child, "wakeup-source") ||
706             /* legacy name */
707             fwnode_property_read_bool(child, "gpio-key,wakeup");
708 
709         button->can_disable =
710             fwnode_property_read_bool(child, "linux,can-disable");
711 
712         if (fwnode_property_read_u32(child, "debounce-interval",
713                      &button->debounce_interval))
714             button->debounce_interval = 5; //如是中断触发的按键,则"debounce-interval"属性无需设置,如是定时轮询方式的则需要设置此间隔时间.
715 
716         button++;
717     }
718 
719     return pdata;
720 }

当在probe函数里遍历每个子节点时,会调用gpio_keys_setup_key函数来设置并获取io口信息.
468 static int gpio_keys_setup_key(struct platform_device *pdev,
469                 struct input_dev *input,
470                 struct gpio_keys_drvdata *ddata,
471                 const struct gpio_keys_button *button,
472                 int idx,
473                 struct fwnode_handle *child)
474 {
        ...
486 
487     if (child) {
488         bdata->gpiod = devm_fwnode_get_gpiod_from_child(dev, NULL,
489                                 child,
490                                 GPIOD_IN,
491                                 desc); 
    // con_id为NULL, 则表示子节点里应用gpios属性来提供io口资源.

如板上有两个按键,一个按键接PA12(作键盘上的UP键), 另一个接PA11(作键盘上的ENTER键).
设备树里的设备节点:

mykeys {
    compatible = "gpio-keys";
    autorepeat = <1>;
    label = "mykeys";

    btn0  {
        label = "btn0";
        gpios = <&pio  0  12  GPIO_ACTIVE_HIGH>;
        linux,code = <KEY_UP>;  
    };

    btn1  {
        label = "btn1";
        gpios = <&pio  0  11  GPIO_ACTIVE_HIGH>;
        linux,code = <KEY_ENTER>;   
    };  
};

更新使用设备树,重启系统后,可以查看到:

^_^ / # cat /proc/bus/input/devices 
I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="mykeys"
P: Phys=gpio-keys/input0
S: Sysfs=/devices/platform/mykeys/input/input1
U: Uniq=
H: Handlers=kbd event1 
B: PROP=0
B: EV=100003
B: KEY=8000000000 10000000

另如按键所接的IO口是没有中断功能的,则可以使用gpio_keys_polled.c设备驱动.

可参考内核源码里的: Documentation/devicetree/bindings/input/gpio-keys.txt 
         Documentation/devicetree/bindings/input/gpio-keys-polled.txt

你可能感兴趣的:(全志H5,Linux-4.11)