16 核心裡gpio-keys裝置驅動的裝置樹描述
阿新 • • 發佈:2019-02-06
此裝置驅動在核心裡配置:
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