keypad: gpio key drive optimization
authorYingyuan Zhu <yingyuan.zhu@amlogic.com>
Thu, 28 Jun 2018 07:54:02 +0000 (15:54 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Thu, 2 Aug 2018 07:22:00 +0000 (00:22 -0700)
PD#169209: keypad: gpio key drive optimization

1.replace the old interface gpio_ with gpiod_.
2.add irq detection mode,can be configured as
 interrupt mode or polling mode through DTS.
3.add keys to eliminate jitter.
4.remove useless code.

Change-Id: I81ef3cd0061e36faa10f58932588ff5031208b25
Signed-off-by: Yingyuan Zhu <yingyuan.zhu@amlogic.com>
16 files changed:
arch/arm64/boot/dts/amlogic/g12a_s905d2_u200.dts
arch/arm64/boot/dts/amlogic/g12a_s905d2_u200_1g.dts
arch/arm64/boot/dts/amlogic/g12a_s905d2_u200_buildroot.dts
arch/arm64/boot/dts/amlogic/g12a_s905d2_u200_drm_buildroot.dts
arch/arm64/boot/dts/amlogic/g12a_s905d2_u220.dts
arch/arm64/boot/dts/amlogic/g12b_a311d_skt.dts
arch/arm64/boot/dts/amlogic/g12b_a311d_w400.dts
arch/arm64/boot/dts/amlogic/g12b_a311d_w400_buildroot.dts
arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts
arch/arm64/boot/dts/amlogic/gxl_p212_1g_hd.dts
arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts
arch/arm64/boot/dts/amlogic/gxl_p230_2g.dts
arch/arm64/boot/dts/amlogic/gxl_p241_1g.dts
arch/arm64/boot/dts/amlogic/gxl_p241_v2-1g.dts
drivers/amlogic/input/keyboard/gpio_keypad.c
drivers/amlogic/input/keyboard/gpio_keypad_old.c [new file with mode: 0644]

index 8ac09a18c19ddb1ee72ccb7894d70f8f20eed013..6754cd8385a985fd2e5b2b44cf442ede3072fd5a 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
        adc_keypad {
index 4f2e6ecc66f99214a0a330426771760268b49ea8..a93ec82f4ddc8152cbbf2edcb210468c088fa038 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
        adc_keypad {
index 365533b0ab7db8cec4eacc9ccc96e00d2590a014..f5332c78a548a113dc7deeac4f55543be4d13c2a 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
        adc_keypad {
index f46a70fb35a3e8e03fa19fd45910730efec16011..c774dcba82d6c218f52f115e55a88b4945000b7b 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
-       };
+               key-gpios = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
 
        adc_keypad {
                compatible = "amlogic, adc_keypad";
index 017abf04132268fe1daf0fcea5558c92c4996ecc..ca6b4c630b3d6b387b7464243c39b34a1794a43f 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
        adc_keypad {
index e52abbd08db541042928b847c0c4b81af98a1e88..1ed8102dd13c22b2482e8ced313f8c0608f57453 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               key-gpios = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
        adc_keypad {
index d0468005ca1262ca3c3ceafc8ccfe7e959861bf3..7949c00e9a60803e478520824204176409791e68 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               key-gpios = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
        adc_keypad {
index 8139f07b5db827eb7fd2808cbc69c12616ff1e1a..0a330f2fa4e20bc21f1f094721182e4697b2b628 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               key-gpios = <&gpio_ao  GPIOAO_3  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
        adc_keypad {
index 36939bb25c9c79e4fe6129a67ee91f3a01c68204..e219ad0e3814a7eb874540ff14407c7af83fb3e2 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
        meson-fb {
                compatible = "amlogic, meson-gxl";
index 2c40f70f0fee8d827883aac5011dfb4767dc9e7f..3a34777700859ddd52aa40c3204956ddb5d7a129 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
        meson-fb {
                compatible = "amlogic, meson-gxl";
index 98d49d7299c82d3911800b52e179fef183f0ed2d..01e81fb9ab7f9b912202870a9a07cb33f0438265 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
-               interrupts = <  0 70 1
-                       0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
        aml_sensor0: aml-sensor@0 {
index c8e8b3950f1cc98546818435600eeb44107f6850..3ed702f286ac66f7a19c98c7f64b6a4f443fdfbe 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;/*"GPIOAO_2";*/
                irq_keyup = <6>;
                irq_keydown = <7>;
+               key-gpios = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
 
 
index c5a275599fdc12c955693ca7e57bba8708f95b4e..ed5256ceadf8404044abd907889fd5ac7365b497 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
        meson-fb {
                compatible = "amlogic, meson-gxl";
index b43d90129241aa3ac0b658b6e00af611493773b2..49605c55a3450bd438678948fad7d97b6b460054 100644 (file)
                key_num = <1>;
                key_name = "power";
                key_code = <116>;
-               key_pin = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
-               interrupts = <0 70 1
-                               0 71 2>;
-               interrupt-names = "irq_keyup", "irq_keydown";
+               key-gpios = <&gpio_ao  GPIOAO_2  GPIO_ACTIVE_HIGH>;
+               detect_mode = <0>;/*0:polling mode, 1:irq mode*/
        };
        meson-fb {
                compatible = "amlogic, meson-gxl";
index 35abea93ba2e961a3d8a6b0430b4a1c353fd8cfd..44e32386af66edf76c01e2cdef6dc5173e8bfad2 100644 (file)
  * more details.
  *
  */
-
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/types.h>
 #include <linux/input.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
 #include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/errno.h>
-#include <linux/irq.h>
-#include <linux/of_irq.h>
-
-#include <asm/irq.h>
 #include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <uapi/linux/input.h>
-#include <linux/major.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
 #include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/of.h>
-#include <linux/amlogic/aml_gpio_consumer.h>
-#include <linux/amlogic/gpio-amlogic.h>
-#include <linux/amlogic/sd.h>
-#include <linux/amlogic/iomap.h>
-#include <linux/amlogic/cpu_version.h>
 #include <linux/amlogic/pm.h>
-#include <linux/of_address.h>
-#include "../../../gpio/gpiolib.h"
-
-#define OFFSET  24
-
-#define MOD_NAME       "gpio_key"
 
 #undef pr_fmt
-#define pr_fmt(fmt) "gpio_key: " fmt
+#define pr_fmt(fmt) "gpio-keypad: " fmt
 
-struct gpio_key {
-       int code;         /* input key code */
-       const char *name;
-       int pin;    /*pin number*/
-       int status; /*0 up ,  1 down*/
-};
+#define DEFAULT_SCAN_PERION    20
+#define        DEFAULT_POLL_MODE       0
+#define KEY_JITTER_COUNT       1
 
-struct gpio_platform_data {
-       struct gpio_key *key;
-       int key_num;
-       int repeat_delay;
-       int repeat_period;
-       int irq_keyup;
-       int irq_keydown;
+struct pin_desc {
+       int current_status;
+       struct gpio_desc *desc;
+       int irq_num;
+       u32 code;
+       const char *name;
 };
 
-struct kp {
-       struct input_dev *input;
-       struct timer_list timer;
-       int config_major;
-       char config_name[20];
-       struct class *config_class;
-       struct device *config_dev;
-       struct gpio_key *keys;
-       int key_num;
-       struct work_struct work_update;
+struct gpio_keypad {
+       int key_size;
+       int use_irq;//1:irq mode ; 0:polling mode
+       int scan_period;
+       int current_irq;
+       int count;
+       int index;
+       struct pin_desc *key;
+       struct pin_desc *current_key;
+       struct timer_list polling_timer;
+       struct input_dev *input_dev;
 };
 
-static struct kp *gp_kp;
-
-int amlogic_gpio_name_map_num(struct platform_device *pdev, const char *value)
-{
-       return of_property_read_string(pdev->dev.of_node, "key_pin",  &value);
-}
-
-
-static void kp_work(struct kp *kp)
-{
-       struct gpio_key *key;
-       int i;
-       int io_status;
-
-       key = kp->keys;
-       for (i = 0; i < kp->key_num; i++) {
-               io_status = gpiod_get_value(gpio_to_desc(key->pin));
-               if (io_status != key->status) {
-                       if (io_status) {
-                               dev_info(&kp->input->dev,
-                                        "key %d up\n", key->code);
-                               input_report_key(kp->input,  key->code, 0);
-                               input_sync(kp->input);
-                       } else {
-                               dev_info(&kp->input->dev,
-                                        "key %d down\n", key->code);
-                               input_report_key(kp->input, key->code, 1);
-                               input_sync(kp->input);
-                       }
-                       key->status = io_status;
-               }
-               key++;
-       }
-}
-
-static void update_work_func(struct work_struct *work)
-{
-       struct kp *kp_data = container_of(work, struct kp, work_update);
-
-       kp_work(kp_data);
-}
-
-/*
- * What we do here is just for loss wakeup key when suspend.
- * In suspend routine ,  the intr is disable.
- * we need do more things to adapt the gpio change.
- */
-int det_pwr_key(void)
-{
-       /*return aml_read_reg32(P_AO_IRQ_STAT) & (1<<8);*/
-       return 0;
-}
-/*Enable gpio interrupt for AO domain interrupt*/
-void set_pwr_key(void)
+static irqreturn_t gpio_irq_handler(int irq, void *data)
 {
-       /* aml_write_reg32(P_AO_IRQ_GPIO_REG,
-        * aml_read_reg32(P_AO_IRQ_GPIO_REG)|(1<<18)|(1<<16)|(0x3<<0));
-        * aml_write_reg32(P_AO_IRQ_MASK_FIQ_SEL,
-        * aml_read_reg32(P_AO_IRQ_MASK_FIQ_SEL)|(1<<8));
-        * aml_set_reg32_mask(P_AO_IRQ_STAT_CLR, 1<<8);
-        */
-}
+       struct gpio_keypad *keypad;
 
-void clr_pwr_key(void)
-{
-       /*aml_set_reg32_mask(P_AO_IRQ_STAT_CLR, 1<<8);*/
-}
-
-
-#ifdef USE_IRQ
-
-static irqreturn_t kp_isr(int irq,  void *data)
-{
-       struct kp *kp_data = (struct kp *)data;
-
-       queue_work(system_freezable_wq, &(kp_data->work_update));
-
-       /* if (!deep_suspend_flag)
-        *      clr_pwr_key();
-        */
+       keypad = (struct gpio_keypad *)data;
+       keypad->current_irq  = irq;
+       keypad->count++;
+       mod_timer(&(keypad->polling_timer),
+                       jiffies+msecs_to_jiffies(20));
        return IRQ_HANDLED;
 }
 
-#else
-void kp_timer_sr(unsigned long data)
+static struct pin_desc *get_current_key(struct gpio_keypad *keypad)
 {
-       struct kp *kp_data = (struct kp *)data;
+       int i;
 
-       queue_work(system_freezable_wq, &(kp_data->work_update));
-       mod_timer(&kp_data->timer, jiffies+msecs_to_jiffies(25));
+       for (i = 0; i < keypad->key_size; i++) {
+               if (keypad->current_irq == keypad->key[i].irq_num)
+                       return &(keypad->key[i]);
+       }
+       return NULL;
 }
-#endif
-static int gpio_key_config_open(struct inode *inode,  struct file *file)
+static void report_key_code(struct gpio_keypad *keypad, int key_status)
 {
-       file->private_data = gp_kp;
-       return 0;
-}
-
-static int gpio_key_config_release(struct inode *inode,  struct file *file)
-{
-       file->private_data = NULL;
-       return 0;
+       struct pin_desc *key;
+
+       if (keypad->count < KEY_JITTER_COUNT)
+               keypad->count++;
+       else {
+               key = keypad->current_key;
+               key->current_status = gpiod_get_value(key->desc);
+               input_report_key(keypad->input_dev,
+                       key->code, key_status);
+               input_sync(keypad->input_dev);
+               if (key_status)
+                       dev_info(&(keypad->input_dev->dev),
+                               "key %d down.\n",
+                               key->code);
+               else
+                       dev_info(&(keypad->input_dev->dev),
+                               "key %d up.\n",
+                               key->code);
+               keypad->count = 0;
+       }
 }
-
-static const struct file_operations keypad_fops = {
-       .owner      = THIS_MODULE,
-       .open       = gpio_key_config_open,
-       .release    = gpio_key_config_release,
-};
-
-static int register_keypad_dev(struct kp  *kp)
+static void polling_timer_handler(unsigned long data)
 {
-       int ret = 0;
-       char name[] = "gpio_keyboard";
+       struct gpio_keypad *keypad;
+       struct pin_desc *key;
+       int i;
 
-       strncpy(kp->config_name, name, sizeof(name));
-       ret = register_chrdev(0, kp->config_name, &keypad_fops);
-       if (ret <= 0) {
-               dev_info(&kp->input->dev, "register char device error\n");
-               return  ret;
+       keypad = (struct gpio_keypad *)data;
+       if (keypad->use_irq) {//irq mode
+               keypad->current_key = get_current_key(keypad);
+               if (!(keypad->current_key))
+                       return;
+               key = keypad->current_key;
+               if (key->current_status != gpiod_get_value(key->desc))
+                       report_key_code(keypad, key->current_status);
+               else
+                       keypad->count = 0;
+               if (key->current_status == 0)
+                       mod_timer(&(keypad->polling_timer),
+                               jiffies+msecs_to_jiffies(keypad->scan_period));
+       } else {//polling mode
+               for (i = 0; i < keypad->key_size; i++) {
+                       if (keypad->key[i].current_status !=
+                                       gpiod_get_value(keypad->key[i].desc)) {
+                               keypad->index = i;
+                               keypad->current_key = &(keypad->key[i]);
+                               report_key_code(keypad,
+                                       keypad->key[i].current_status);
+                       } else if (keypad->index ==  i)
+                               keypad->count = 0;
+               mod_timer(&(keypad->polling_timer),
+                       jiffies+msecs_to_jiffies(keypad->scan_period));
+               }
        }
-       kp->config_major = ret;
-       dev_info(&kp->input->dev, "gpio keypad major:%d\n", ret);
-       kp->config_class = class_create(THIS_MODULE, kp->config_name);
-       kp->config_dev = device_create(kp->config_class, NULL,
-               MKDEV(kp->config_major, 0), NULL, kp->config_name);
-       return ret;
 }
 
-static int gpio_key_probe(struct platform_device *pdev)
+static int meson_gpio_kp_probe(struct platform_device *pdev)
 {
-       const char *str;
-       struct kp *kp;
-       struct input_dev *input_dev;
-       int i,  ret,  key_size;
-       struct gpio_key *key;
-       struct gpio_platform_data *pdata = NULL;
        struct gpio_desc *desc;
-       int *key_param = NULL;
-       int state = -EINVAL;
-#ifdef USE_IRQ
-       int irq_keyup;
-       int irq_keydown;
-#endif
-
-       int gpio_highz = 0;
-
-       if (!pdev->dev.of_node) {
-               dev_info(&pdev->dev, "gpio_key: pdev->dev.of_node == NULL!\n");
-               state = -EINVAL;
-               goto get_key_node_fail;
-       }
-       ret = of_property_read_u32(pdev->dev.of_node, "key_num", &key_size);
-       if (ret) {
-               dev_info(&pdev->dev, "gpio_key: failed to get key_num!\n");
-               state = -EINVAL;
-               goto get_key_node_fail;
-       }
+       int ret, i;
+       struct input_dev *input_dev;
+       struct gpio_keypad *keypad;
 
-       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
-       if (!pdata) {
-               state = -EINVAL;
-               goto get_key_node_fail;
+       if (!(pdev->dev.of_node)) {
+               dev_err(&pdev->dev,
+                       "pdev->dev.of_node == NULL!\n");
+               return -EINVAL;
        }
-
-       ret = of_property_read_bool(pdev->dev.of_node,  "gpio_high_z");
+       keypad = devm_kzalloc(&pdev->dev,
+               sizeof(struct gpio_keypad), GFP_KERNEL);
+       if (!keypad)
+               return -EINVAL;
+       ret = of_property_read_u32(pdev->dev.of_node,
+               "detect_mode", &(keypad->use_irq));
+       if (ret)
+               //The default mode is polling.
+               keypad->use_irq = DEFAULT_POLL_MODE;
+       ret = of_property_read_u32(pdev->dev.of_node,
+               "scan_period", &(keypad->scan_period));
+       if (ret)
+               //The default scan period is 20.
+               keypad->scan_period = DEFAULT_SCAN_PERION;
+       ret = of_property_read_u32(pdev->dev.of_node,
+               "key_num", &(keypad->key_size));
        if (ret) {
-               gpio_highz = 1;
-               dev_info(&pdev->dev, "gpio request set to High-Z status\n");
-       }
-
-       pdata->key = kcalloc(key_size, sizeof(*(pdata->key)), GFP_KERNEL);
-       if (!(pdata->key)) {
-               dev_err(&pdev->dev,  "platform key is required!\n");
-               goto get_key_mem_fail;
+               dev_err(&pdev->dev,
+                       "failed to get key_num!\n");
+               return -EINVAL;
        }
-
-       pdata->key_num = key_size;
-       for (i = 0; i < key_size; i++) {
-               ret = of_property_read_string_index(pdev->dev.of_node,
-                        "key_name", i, &(pdata->key[i].name));
+       keypad->key = devm_kzalloc(&pdev->dev,
+               (keypad->key_size)*sizeof(*(keypad->key)), GFP_KERNEL);
+       if (!(keypad->key))
+               return -EINVAL;
+       for (i = 0; i < keypad->key_size; i++) {
+               //get all gpio desc.
+               desc = devm_gpiod_get_index(&pdev->dev, "key", i, GPIOD_IN);
+               if (!desc)
+                       return -EINVAL;
+               keypad->key[i].desc = desc;
+               //The gpio default is high level.
+               keypad->key[i].current_status = 1;
+               ret = of_property_read_u32_index(pdev->dev.of_node,
+               "key_code", i, &(keypad->key[i].code));
                if (ret < 0) {
-                       dev_info(&pdev->dev,
-                                "gpio_key: find key_name=%d finished\n", i);
-                       break;
+                       dev_err(&pdev->dev,
+                               "find key_code=%d finished\n", i);
+                       return -EINVAL;
                }
-       }
-       key_param = kzalloc((sizeof(*key_param))*(pdata->key_num), GFP_KERNEL);
-       if (!key_param)
-               goto get_param_mem_fail;
-       ret = of_property_read_u32_array(pdev->dev.of_node,
-                "key_code", key_param,  pdata->key_num);
-       if (ret) {
-               dev_info(&pdev->dev, "gpio_key: failed to get key_code!\n");
-               goto get_key_param_failed;
-       }
-
-       for (i = 0; i < pdata->key_num; i++) {
-               pdata->key[i].code = *(key_param+i);
-               pdata->key[i].status = -1;
-       }
-
-#ifdef USE_IRQ
-               pdata->irq_keyup = irq_of_parse_and_map(pdev->dev.of_node, 0);
-               pdata->irq_keydown = irq_of_parse_and_map(pdev->dev.of_node, 1);
-               pdata->irq_keyup = irq_keyup;
-               pdata->irq_keydown = irq_keydown;
-               pr_info("irq_keyup:%d,irq_keydown:%d\n",
-                               pdata->irq_keyup, pdata->irq_keydown);
-#endif
-
-       for (i = 0; i < key_size; i++) {
                ret = of_property_read_string_index(pdev->dev.of_node,
-                       "key_pin", i, &str);
-               dev_info(&pdev->dev, "gpio_key: %d name(%s) pin(%s)\n",
-                        i, (pdata->key[i].name), str);
-               if (ret < 0) {
-                       dev_info(&pdev->dev,
-                                "gpio_key: find key_name=%d finished\n", i);
-                       break;
-               }
-               ret = amlogic_gpio_name_map_num(pdev, str);
-               dev_info(&pdev->dev, "amlogic_gpio_name_map_num pin %d!%s::\n",
-                        ret, str);
+                       "key_name", i, &(keypad->key[i].name));
                if (ret < 0) {
-                       dev_info(&pdev->dev, "gpio_key bad pin !\n");
-                       goto get_key_param_failed;
+                       dev_err(&pdev->dev,
+                               "find key_name=%d finished\n", i);
+                       return -EINVAL;
                }
-               desc = of_get_named_gpiod_flags(pdev->dev.of_node,
-                       "key_pin",  i,  NULL);
-               pdata->key[i].pin = desc_to_gpio(desc);
-               dev_info(&pdev->dev, "gpio_key: %d %s(%d)\n", i,
-                        (pdata->key[i].name),  pdata->key[i].pin);
-               /*pdata->key[i].pin = ret;*/
-               gpio_request(pdata->key[i].pin,  MOD_NAME);
-               if (!gpio_highz) {
-                       gpio_direction_input(pdata->key[i].pin);
-                       gpiod_set_pull(desc, GPIOD_PULL_UP);
-               }
-#ifdef USE_IRQ
-               gpio_for_irq(pdata->key[i].pin,
-               AML_GPIO_IRQ(irq_keyup,  FILTER_NUM7, IRQF_TRIGGER_RISING));
-               gpio_for_irq(pdata->key[i].pin,
-               AML_GPIO_IRQ(irq_keydown,  FILTER_NUM7, IRQF_TRIGGER_FALLING));
-#endif
+               gpiod_direction_input(keypad->key[i].desc);
+               gpiod_set_pull(keypad->key[i].desc, GPIOD_PULL_UP);
        }
-
-       kp = kzalloc(sizeof(struct kp),  GFP_KERNEL);
+       //input
        input_dev = input_allocate_device();
-       if (!kp || !input_dev) {
-               kfree(kp);
-               input_free_device(input_dev);
-               state = -ENOMEM;
-               goto get_key_param_failed;
-       }
-       gp_kp = kp;
-       platform_set_drvdata(pdev,  pdata);
-       kp->input = input_dev;
-       INIT_WORK(&(kp->work_update),  update_work_func);
-#ifdef USE_IRQ
-       if (request_irq(irq_keyup, kp_isr, IRQF_DISABLED,
-                        "irq_keyup",  kp)) {
-               dev_info(&pdev->dev,  "Failed to request gpio key up irq.\n");
-               kfree(kp);
-               input_free_device(input_dev);
-               state = -EINVAL;
-               goto get_key_param_failed;
-       }
-
-       if (request_irq(irq_keydown, kp_isr, IRQF_DISABLED,
-                "irq_keydown",  kp)) {
-               dev_info(&pdev->dev,  "Failed to request gpio key down irq.\n");
-               kfree(kp);
-               input_free_device(input_dev);
-               state = -EINVAL;
-               goto get_key_param_failed;
-       }
-#else
-       dev_info(&pdev->dev, "start setup_timer");
-       setup_timer(&kp->timer,  kp_timer_sr,  (unsigned long) kp);
-       mod_timer(&kp->timer,  jiffies+msecs_to_jiffies(100));
-#endif
-       /* setup input device */
+       if (!input_dev)
+               return -EINVAL;
        set_bit(EV_KEY,  input_dev->evbit);
        set_bit(EV_REP,  input_dev->evbit);
-       kp->keys = pdata->key;
-       kp->key_num = pdata->key_num;
-       key = pdata->key;
-
-       for (i = 0; i < kp->key_num; i++) {
-               set_bit(pdata->key[i].code,  input_dev->keybit);
-               dev_info(&pdev->dev, "%s key(%d) registed.\n",
-                        key->name, pdata->key[i].code);
-       }
        input_dev->name = "gpio_keypad";
        input_dev->phys = "gpio_keypad/input0";
        input_dev->dev.parent = &pdev->dev;
-
        input_dev->id.bustype = BUS_ISA;
        input_dev->id.vendor = 0x0001;
        input_dev->id.product = 0x0001;
        input_dev->id.version = 0x0100;
-
        input_dev->rep[REP_DELAY] = 0xffffffff;
        input_dev->rep[REP_PERIOD] = 0xffffffff;
-
        input_dev->keycodesize = sizeof(unsigned short);
        input_dev->keycodemax = 0x1ff;
-       ret = input_register_device(kp->input);
+       keypad->input_dev = input_dev;
+       ret = input_register_device(keypad->input_dev);
        if (ret < 0) {
-               dev_err(&pdev->dev,  "Unable to register keypad input device.\n");
-               kfree(kp);
-               input_free_device(input_dev);
-               state = -EINVAL;
-               goto get_key_param_failed;
+               input_free_device(keypad->input_dev);
+               return -EINVAL;
+       }
+       platform_set_drvdata(pdev, keypad);
+       keypad->count = 0;
+       keypad->index = -1;
+       setup_timer(&(keypad->polling_timer),
+               polling_timer_handler, (unsigned long) keypad);
+       if (keypad->use_irq) {
+               for (i = 0; i < keypad->key_size; i++) {
+                       keypad->key[i].irq_num =
+                               gpiod_to_irq(keypad->key[i].desc);
+                       ret = devm_request_irq(&pdev->dev,
+                               keypad->key[i].irq_num,
+                               gpio_irq_handler, IRQF_TRIGGER_FALLING,
+                               "gpio_keypad", keypad);
+                       if (ret) {
+                               dev_err(&pdev->dev,
+                                       "Requesting irq failed!\n");
+                               input_free_device(keypad->input_dev);
+                               del_timer(&(keypad->polling_timer));
+                               return -EINVAL;
+                       }
+               }
+       } else {
+               mod_timer(&(keypad->polling_timer),
+                       jiffies+msecs_to_jiffies(keypad->scan_period));
        }
-/*set_pwr_key();*/
-       dev_info(&pdev->dev, "gpio keypad register input device completed.\n");
-       register_keypad_dev(gp_kp);
-       kfree(key_param);
        return 0;
-
-get_key_param_failed:
-       kfree(key_param);
-get_param_mem_fail:
-       kfree(pdata->key);
-get_key_mem_fail:
-       kfree(pdata);
-get_key_node_fail:
-       return state;
 }
 
-static int gpio_key_remove(struct platform_device *pdev)
+static int meson_gpio_kp_remove(struct platform_device *pdev)
 {
-       struct gpio_platform_data *pdata = platform_get_drvdata(pdev);
-       struct kp *kp = gp_kp;
+       struct gpio_keypad *keypad;
 
-       input_unregister_device(kp->input);
-       input_free_device(kp->input);
-       unregister_chrdev(kp->config_major,  kp->config_name);
-       if (kp->config_class) {
-               if (kp->config_dev)
-                       device_destroy(kp->config_class,
-                           MKDEV(kp->config_major, 0));
-               class_destroy(kp->config_class);
-       }
-       kfree(kp);
-#ifdef CONFIG_OF
-       kfree(pdata->key);
-       kfree(pdata);
-#endif
-       gp_kp = NULL;
+       keypad = platform_get_drvdata(pdev);
+       input_unregister_device(keypad->input_dev);
+       input_free_device(keypad->input_dev);
+       del_timer(&(keypad->polling_timer));
        return 0;
 }
 
-static int gpio_key_suspend(struct platform_device *dev,  pm_message_t state)
+static const struct of_device_id key_dt_match[] = {
+       {       .compatible = "amlogic, gpio_keypad", },
+       {},
+};
+
+static int meson_gpio_kp_suspend(struct platform_device *dev,
+       pm_message_t state)
 {
+       int i;
+       struct gpio_keypad *pdata;
+
+       pdata = (struct gpio_keypad *)platform_get_drvdata(dev);
+       if (pdata->use_irq) {
+               for (i = 0; i < pdata->key_size; i++)
+               disable_irq_nosync(pdata->key[i].irq_num);
+       } else
+               del_timer(&(pdata->polling_timer));
        return 0;
 }
 
-static int gpio_key_resume(struct platform_device *dev)
+static int meson_gpio_kp_resume(struct platform_device *dev)
 {
        int i;
-       struct gpio_platform_data *pdata;
-
-       pdata = (struct gpio_platform_data *)platform_get_drvdata(dev);
-
+       struct gpio_keypad *pdata;
+
+       pdata = (struct gpio_keypad *)platform_get_drvdata(dev);
+       if (pdata->use_irq) {
+               for (i = 0; i < pdata->key_size; i++)
+                       enable_irq(pdata->key[i].irq_num);
+       } else
+               mod_timer(&(pdata->polling_timer),
+                       jiffies+msecs_to_jiffies(5));
        if (get_resume_method() == POWER_KEY_WAKEUP) {
-               for (i = 0; i < pdata->key_num; i++) {
+               for (i = 0; i < pdata->key_size; i++) {
                        if (pdata->key[i].code == KEY_POWER) {
                                pr_info("gpio keypad wakeup\n");
-
-                               input_report_key(gp_kp->input,  KEY_POWER,  1);
-                               input_sync(gp_kp->input);
-                               input_report_key(gp_kp->input,  KEY_POWER,  0);
-                               input_sync(gp_kp->input);
-
+                               input_report_key(pdata->input_dev,
+                                       KEY_POWER,  1);
+                               input_sync(pdata->input_dev);
+                               input_report_key(pdata->input_dev,
+                                       KEY_POWER,  0);
+                               input_sync(pdata->input_dev);
                                break;
                        }
                }
@@ -466,40 +305,18 @@ static int gpio_key_resume(struct platform_device *dev)
        return 0;
 }
 
-#ifdef CONFIG_OF
-static const struct of_device_id key_dt_match[] = {
-       {       .compatible = "amlogic, gpio_keypad", },
-       {},
-};
-#else
-#define key_dt_match NULL
-#endif
-
-static struct platform_driver gpio_driver = {
-       .probe = gpio_key_probe,
-       .remove = gpio_key_remove,
-       .suspend = gpio_key_suspend,
-       .resume = gpio_key_resume,
+static struct platform_driver meson_gpio_kp_driver = {
+       .probe = meson_gpio_kp_probe,
+       .remove = meson_gpio_kp_remove,
+       .suspend = meson_gpio_kp_suspend,
+       .resume = meson_gpio_kp_resume,
        .driver = {
-               .name = "gpio-key",
+               .name = "gpio-keypad",
                .of_match_table = key_dt_match,
        },
 };
 
-static int __init gpio_key_init(void)
-{
-       return platform_driver_register(&gpio_driver);
-}
-
-static void __exit gpio_key_exit(void)
-{
-       platform_driver_unregister(&gpio_driver);
-}
-
-module_init(gpio_key_init);
-module_exit(gpio_key_exit);
-
-MODULE_AUTHOR("Frank Chen");
+module_platform_driver(meson_gpio_kp_driver);
+MODULE_AUTHOR("Amlogic");
 MODULE_DESCRIPTION("GPIO Keypad Driver");
 MODULE_LICENSE("GPL");
-
diff --git a/drivers/amlogic/input/keyboard/gpio_keypad_old.c b/drivers/amlogic/input/keyboard/gpio_keypad_old.c
new file mode 100644 (file)
index 0000000..35abea9
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * drivers/amlogic/input/keyboard/gpio_keypad.c
+ *
+ * Copyright (C) 2017 Amlogic, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/of_irq.h>
+
+#include <asm/irq.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <uapi/linux/input.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/of.h>
+#include <linux/amlogic/aml_gpio_consumer.h>
+#include <linux/amlogic/gpio-amlogic.h>
+#include <linux/amlogic/sd.h>
+#include <linux/amlogic/iomap.h>
+#include <linux/amlogic/cpu_version.h>
+#include <linux/amlogic/pm.h>
+#include <linux/of_address.h>
+#include "../../../gpio/gpiolib.h"
+
+#define OFFSET  24
+
+#define MOD_NAME       "gpio_key"
+
+#undef pr_fmt
+#define pr_fmt(fmt) "gpio_key: " fmt
+
+struct gpio_key {
+       int code;         /* input key code */
+       const char *name;
+       int pin;    /*pin number*/
+       int status; /*0 up ,  1 down*/
+};
+
+struct gpio_platform_data {
+       struct gpio_key *key;
+       int key_num;
+       int repeat_delay;
+       int repeat_period;
+       int irq_keyup;
+       int irq_keydown;
+};
+
+struct kp {
+       struct input_dev *input;
+       struct timer_list timer;
+       int config_major;
+       char config_name[20];
+       struct class *config_class;
+       struct device *config_dev;
+       struct gpio_key *keys;
+       int key_num;
+       struct work_struct work_update;
+};
+
+static struct kp *gp_kp;
+
+int amlogic_gpio_name_map_num(struct platform_device *pdev, const char *value)
+{
+       return of_property_read_string(pdev->dev.of_node, "key_pin",  &value);
+}
+
+
+static void kp_work(struct kp *kp)
+{
+       struct gpio_key *key;
+       int i;
+       int io_status;
+
+       key = kp->keys;
+       for (i = 0; i < kp->key_num; i++) {
+               io_status = gpiod_get_value(gpio_to_desc(key->pin));
+               if (io_status != key->status) {
+                       if (io_status) {
+                               dev_info(&kp->input->dev,
+                                        "key %d up\n", key->code);
+                               input_report_key(kp->input,  key->code, 0);
+                               input_sync(kp->input);
+                       } else {
+                               dev_info(&kp->input->dev,
+                                        "key %d down\n", key->code);
+                               input_report_key(kp->input, key->code, 1);
+                               input_sync(kp->input);
+                       }
+                       key->status = io_status;
+               }
+               key++;
+       }
+}
+
+static void update_work_func(struct work_struct *work)
+{
+       struct kp *kp_data = container_of(work, struct kp, work_update);
+
+       kp_work(kp_data);
+}
+
+/*
+ * What we do here is just for loss wakeup key when suspend.
+ * In suspend routine ,  the intr is disable.
+ * we need do more things to adapt the gpio change.
+ */
+int det_pwr_key(void)
+{
+       /*return aml_read_reg32(P_AO_IRQ_STAT) & (1<<8);*/
+       return 0;
+}
+/*Enable gpio interrupt for AO domain interrupt*/
+void set_pwr_key(void)
+{
+       /* aml_write_reg32(P_AO_IRQ_GPIO_REG,
+        * aml_read_reg32(P_AO_IRQ_GPIO_REG)|(1<<18)|(1<<16)|(0x3<<0));
+        * aml_write_reg32(P_AO_IRQ_MASK_FIQ_SEL,
+        * aml_read_reg32(P_AO_IRQ_MASK_FIQ_SEL)|(1<<8));
+        * aml_set_reg32_mask(P_AO_IRQ_STAT_CLR, 1<<8);
+        */
+}
+
+void clr_pwr_key(void)
+{
+       /*aml_set_reg32_mask(P_AO_IRQ_STAT_CLR, 1<<8);*/
+}
+
+
+#ifdef USE_IRQ
+
+static irqreturn_t kp_isr(int irq,  void *data)
+{
+       struct kp *kp_data = (struct kp *)data;
+
+       queue_work(system_freezable_wq, &(kp_data->work_update));
+
+       /* if (!deep_suspend_flag)
+        *      clr_pwr_key();
+        */
+       return IRQ_HANDLED;
+}
+
+#else
+void kp_timer_sr(unsigned long data)
+{
+       struct kp *kp_data = (struct kp *)data;
+
+       queue_work(system_freezable_wq, &(kp_data->work_update));
+       mod_timer(&kp_data->timer, jiffies+msecs_to_jiffies(25));
+}
+#endif
+static int gpio_key_config_open(struct inode *inode,  struct file *file)
+{
+       file->private_data = gp_kp;
+       return 0;
+}
+
+static int gpio_key_config_release(struct inode *inode,  struct file *file)
+{
+       file->private_data = NULL;
+       return 0;
+}
+
+static const struct file_operations keypad_fops = {
+       .owner      = THIS_MODULE,
+       .open       = gpio_key_config_open,
+       .release    = gpio_key_config_release,
+};
+
+static int register_keypad_dev(struct kp  *kp)
+{
+       int ret = 0;
+       char name[] = "gpio_keyboard";
+
+       strncpy(kp->config_name, name, sizeof(name));
+       ret = register_chrdev(0, kp->config_name, &keypad_fops);
+       if (ret <= 0) {
+               dev_info(&kp->input->dev, "register char device error\n");
+               return  ret;
+       }
+       kp->config_major = ret;
+       dev_info(&kp->input->dev, "gpio keypad major:%d\n", ret);
+       kp->config_class = class_create(THIS_MODULE, kp->config_name);
+       kp->config_dev = device_create(kp->config_class, NULL,
+               MKDEV(kp->config_major, 0), NULL, kp->config_name);
+       return ret;
+}
+
+static int gpio_key_probe(struct platform_device *pdev)
+{
+       const char *str;
+       struct kp *kp;
+       struct input_dev *input_dev;
+       int i,  ret,  key_size;
+       struct gpio_key *key;
+       struct gpio_platform_data *pdata = NULL;
+       struct gpio_desc *desc;
+       int *key_param = NULL;
+       int state = -EINVAL;
+#ifdef USE_IRQ
+       int irq_keyup;
+       int irq_keydown;
+#endif
+
+       int gpio_highz = 0;
+
+       if (!pdev->dev.of_node) {
+               dev_info(&pdev->dev, "gpio_key: pdev->dev.of_node == NULL!\n");
+               state = -EINVAL;
+               goto get_key_node_fail;
+       }
+       ret = of_property_read_u32(pdev->dev.of_node, "key_num", &key_size);
+       if (ret) {
+               dev_info(&pdev->dev, "gpio_key: failed to get key_num!\n");
+               state = -EINVAL;
+               goto get_key_node_fail;
+       }
+
+       pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               state = -EINVAL;
+               goto get_key_node_fail;
+       }
+
+       ret = of_property_read_bool(pdev->dev.of_node,  "gpio_high_z");
+       if (ret) {
+               gpio_highz = 1;
+               dev_info(&pdev->dev, "gpio request set to High-Z status\n");
+       }
+
+       pdata->key = kcalloc(key_size, sizeof(*(pdata->key)), GFP_KERNEL);
+       if (!(pdata->key)) {
+               dev_err(&pdev->dev,  "platform key is required!\n");
+               goto get_key_mem_fail;
+       }
+
+       pdata->key_num = key_size;
+       for (i = 0; i < key_size; i++) {
+               ret = of_property_read_string_index(pdev->dev.of_node,
+                        "key_name", i, &(pdata->key[i].name));
+               if (ret < 0) {
+                       dev_info(&pdev->dev,
+                                "gpio_key: find key_name=%d finished\n", i);
+                       break;
+               }
+       }
+       key_param = kzalloc((sizeof(*key_param))*(pdata->key_num), GFP_KERNEL);
+       if (!key_param)
+               goto get_param_mem_fail;
+       ret = of_property_read_u32_array(pdev->dev.of_node,
+                "key_code", key_param,  pdata->key_num);
+       if (ret) {
+               dev_info(&pdev->dev, "gpio_key: failed to get key_code!\n");
+               goto get_key_param_failed;
+       }
+
+       for (i = 0; i < pdata->key_num; i++) {
+               pdata->key[i].code = *(key_param+i);
+               pdata->key[i].status = -1;
+       }
+
+#ifdef USE_IRQ
+               pdata->irq_keyup = irq_of_parse_and_map(pdev->dev.of_node, 0);
+               pdata->irq_keydown = irq_of_parse_and_map(pdev->dev.of_node, 1);
+               pdata->irq_keyup = irq_keyup;
+               pdata->irq_keydown = irq_keydown;
+               pr_info("irq_keyup:%d,irq_keydown:%d\n",
+                               pdata->irq_keyup, pdata->irq_keydown);
+#endif
+
+       for (i = 0; i < key_size; i++) {
+               ret = of_property_read_string_index(pdev->dev.of_node,
+                       "key_pin", i, &str);
+               dev_info(&pdev->dev, "gpio_key: %d name(%s) pin(%s)\n",
+                        i, (pdata->key[i].name), str);
+               if (ret < 0) {
+                       dev_info(&pdev->dev,
+                                "gpio_key: find key_name=%d finished\n", i);
+                       break;
+               }
+               ret = amlogic_gpio_name_map_num(pdev, str);
+               dev_info(&pdev->dev, "amlogic_gpio_name_map_num pin %d!%s::\n",
+                        ret, str);
+               if (ret < 0) {
+                       dev_info(&pdev->dev, "gpio_key bad pin !\n");
+                       goto get_key_param_failed;
+               }
+               desc = of_get_named_gpiod_flags(pdev->dev.of_node,
+                       "key_pin",  i,  NULL);
+               pdata->key[i].pin = desc_to_gpio(desc);
+               dev_info(&pdev->dev, "gpio_key: %d %s(%d)\n", i,
+                        (pdata->key[i].name),  pdata->key[i].pin);
+               /*pdata->key[i].pin = ret;*/
+               gpio_request(pdata->key[i].pin,  MOD_NAME);
+               if (!gpio_highz) {
+                       gpio_direction_input(pdata->key[i].pin);
+                       gpiod_set_pull(desc, GPIOD_PULL_UP);
+               }
+#ifdef USE_IRQ
+               gpio_for_irq(pdata->key[i].pin,
+               AML_GPIO_IRQ(irq_keyup,  FILTER_NUM7, IRQF_TRIGGER_RISING));
+               gpio_for_irq(pdata->key[i].pin,
+               AML_GPIO_IRQ(irq_keydown,  FILTER_NUM7, IRQF_TRIGGER_FALLING));
+#endif
+       }
+
+       kp = kzalloc(sizeof(struct kp),  GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!kp || !input_dev) {
+               kfree(kp);
+               input_free_device(input_dev);
+               state = -ENOMEM;
+               goto get_key_param_failed;
+       }
+       gp_kp = kp;
+       platform_set_drvdata(pdev,  pdata);
+       kp->input = input_dev;
+       INIT_WORK(&(kp->work_update),  update_work_func);
+#ifdef USE_IRQ
+       if (request_irq(irq_keyup, kp_isr, IRQF_DISABLED,
+                        "irq_keyup",  kp)) {
+               dev_info(&pdev->dev,  "Failed to request gpio key up irq.\n");
+               kfree(kp);
+               input_free_device(input_dev);
+               state = -EINVAL;
+               goto get_key_param_failed;
+       }
+
+       if (request_irq(irq_keydown, kp_isr, IRQF_DISABLED,
+                "irq_keydown",  kp)) {
+               dev_info(&pdev->dev,  "Failed to request gpio key down irq.\n");
+               kfree(kp);
+               input_free_device(input_dev);
+               state = -EINVAL;
+               goto get_key_param_failed;
+       }
+#else
+       dev_info(&pdev->dev, "start setup_timer");
+       setup_timer(&kp->timer,  kp_timer_sr,  (unsigned long) kp);
+       mod_timer(&kp->timer,  jiffies+msecs_to_jiffies(100));
+#endif
+       /* setup input device */
+       set_bit(EV_KEY,  input_dev->evbit);
+       set_bit(EV_REP,  input_dev->evbit);
+       kp->keys = pdata->key;
+       kp->key_num = pdata->key_num;
+       key = pdata->key;
+
+       for (i = 0; i < kp->key_num; i++) {
+               set_bit(pdata->key[i].code,  input_dev->keybit);
+               dev_info(&pdev->dev, "%s key(%d) registed.\n",
+                        key->name, pdata->key[i].code);
+       }
+       input_dev->name = "gpio_keypad";
+       input_dev->phys = "gpio_keypad/input0";
+       input_dev->dev.parent = &pdev->dev;
+
+       input_dev->id.bustype = BUS_ISA;
+       input_dev->id.vendor = 0x0001;
+       input_dev->id.product = 0x0001;
+       input_dev->id.version = 0x0100;
+
+       input_dev->rep[REP_DELAY] = 0xffffffff;
+       input_dev->rep[REP_PERIOD] = 0xffffffff;
+
+       input_dev->keycodesize = sizeof(unsigned short);
+       input_dev->keycodemax = 0x1ff;
+       ret = input_register_device(kp->input);
+       if (ret < 0) {
+               dev_err(&pdev->dev,  "Unable to register keypad input device.\n");
+               kfree(kp);
+               input_free_device(input_dev);
+               state = -EINVAL;
+               goto get_key_param_failed;
+       }
+/*set_pwr_key();*/
+       dev_info(&pdev->dev, "gpio keypad register input device completed.\n");
+       register_keypad_dev(gp_kp);
+       kfree(key_param);
+       return 0;
+
+get_key_param_failed:
+       kfree(key_param);
+get_param_mem_fail:
+       kfree(pdata->key);
+get_key_mem_fail:
+       kfree(pdata);
+get_key_node_fail:
+       return state;
+}
+
+static int gpio_key_remove(struct platform_device *pdev)
+{
+       struct gpio_platform_data *pdata = platform_get_drvdata(pdev);
+       struct kp *kp = gp_kp;
+
+       input_unregister_device(kp->input);
+       input_free_device(kp->input);
+       unregister_chrdev(kp->config_major,  kp->config_name);
+       if (kp->config_class) {
+               if (kp->config_dev)
+                       device_destroy(kp->config_class,
+                           MKDEV(kp->config_major, 0));
+               class_destroy(kp->config_class);
+       }
+       kfree(kp);
+#ifdef CONFIG_OF
+       kfree(pdata->key);
+       kfree(pdata);
+#endif
+       gp_kp = NULL;
+       return 0;
+}
+
+static int gpio_key_suspend(struct platform_device *dev,  pm_message_t state)
+{
+       return 0;
+}
+
+static int gpio_key_resume(struct platform_device *dev)
+{
+       int i;
+       struct gpio_platform_data *pdata;
+
+       pdata = (struct gpio_platform_data *)platform_get_drvdata(dev);
+
+       if (get_resume_method() == POWER_KEY_WAKEUP) {
+               for (i = 0; i < pdata->key_num; i++) {
+                       if (pdata->key[i].code == KEY_POWER) {
+                               pr_info("gpio keypad wakeup\n");
+
+                               input_report_key(gp_kp->input,  KEY_POWER,  1);
+                               input_sync(gp_kp->input);
+                               input_report_key(gp_kp->input,  KEY_POWER,  0);
+                               input_sync(gp_kp->input);
+
+                               break;
+                       }
+               }
+       }
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id key_dt_match[] = {
+       {       .compatible = "amlogic, gpio_keypad", },
+       {},
+};
+#else
+#define key_dt_match NULL
+#endif
+
+static struct platform_driver gpio_driver = {
+       .probe = gpio_key_probe,
+       .remove = gpio_key_remove,
+       .suspend = gpio_key_suspend,
+       .resume = gpio_key_resume,
+       .driver = {
+               .name = "gpio-key",
+               .of_match_table = key_dt_match,
+       },
+};
+
+static int __init gpio_key_init(void)
+{
+       return platform_driver_register(&gpio_driver);
+}
+
+static void __exit gpio_key_exit(void)
+{
+       platform_driver_unregister(&gpio_driver);
+}
+
+module_init(gpio_key_init);
+module_exit(gpio_key_exit);
+
+MODULE_AUTHOR("Frank Chen");
+MODULE_DESCRIPTION("GPIO Keypad Driver");
+MODULE_LICENSE("GPL");
+