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

来源:互联网 发布:小米关闭软件自动更新 编辑:程序博客网 时间:2024/05/16 14:28

此设备驱动适用于连接到一个具有中断功能的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_KEY703 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=0100N: Name="mykeys"P: Phys=gpio-keys/input0S: Sysfs=/devices/platform/mykeys/input/input1U: Uniq=H: Handlers=kbd event1 B: PROP=0B: EV=100003B: KEY=8000000000 10000000

另如按键所接的IO口是没有中断功能的,则可以使用gpio_keys_polled.c设备驱动.可参考内核源码里的: Documentation/devicetree/bindings/input/gpio-keys.txt          Documentation/devicetree/bindings/input/gpio-keys-polled.txt
阅读全文
0 0
原创粉丝点击