linux/drivers/input/misc/hisi_powerkey.c
<<
>>
Prefs
   1/*
   2 * Hisilicon PMIC powerkey driver
   3 *
   4 * Copyright (C) 2013 Hisilicon Ltd.
   5 * Copyright (C) 2015, 2016 Linaro Ltd.
   6 *
   7 * This file is subject to the terms and conditions of the GNU General
   8 * Public License. See the file "COPYING" in the main directory of this
   9 * archive for more details.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 */
  16
  17#include <linux/platform_device.h>
  18#include <linux/interrupt.h>
  19#include <linux/reboot.h>
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22#include <linux/of_irq.h>
  23#include <linux/input.h>
  24#include <linux/slab.h>
  25
  26/* the held interrupt will trigger after 4 seconds */
  27#define MAX_HELD_TIME   (4 * MSEC_PER_SEC)
  28
  29static irqreturn_t hi65xx_power_press_isr(int irq, void *q)
  30{
  31        struct input_dev *input = q;
  32
  33        pm_wakeup_event(input->dev.parent, MAX_HELD_TIME);
  34        input_report_key(input, KEY_POWER, 1);
  35        input_sync(input);
  36
  37        return IRQ_HANDLED;
  38}
  39
  40static irqreturn_t hi65xx_power_release_isr(int irq, void *q)
  41{
  42        struct input_dev *input = q;
  43
  44        pm_wakeup_event(input->dev.parent, MAX_HELD_TIME);
  45        input_report_key(input, KEY_POWER, 0);
  46        input_sync(input);
  47
  48        return IRQ_HANDLED;
  49}
  50
  51static irqreturn_t hi65xx_restart_toggle_isr(int irq, void *q)
  52{
  53        struct input_dev *input = q;
  54        int value = test_bit(KEY_RESTART, input->key);
  55
  56        pm_wakeup_event(input->dev.parent, MAX_HELD_TIME);
  57        input_report_key(input, KEY_RESTART, !value);
  58        input_sync(input);
  59
  60        return IRQ_HANDLED;
  61}
  62
  63static const struct {
  64        const char *name;
  65        irqreturn_t (*handler)(int irq, void *q);
  66} hi65xx_irq_info[] = {
  67        { "down", hi65xx_power_press_isr },
  68        { "up", hi65xx_power_release_isr },
  69        { "hold 4s", hi65xx_restart_toggle_isr },
  70};
  71
  72static int hi65xx_powerkey_probe(struct platform_device *pdev)
  73{
  74        struct device *dev = &pdev->dev;
  75        struct input_dev *input;
  76        int irq, i, error;
  77
  78        input = devm_input_allocate_device(dev);
  79        if (!input) {
  80                dev_err(dev, "failed to allocate input device\n");
  81                return -ENOMEM;
  82        }
  83
  84        input->phys = "hisi_on/input0";
  85        input->name = "HISI 65xx PowerOn Key";
  86
  87        input_set_capability(input, EV_KEY, KEY_POWER);
  88        input_set_capability(input, EV_KEY, KEY_RESTART);
  89
  90        for (i = 0; i < ARRAY_SIZE(hi65xx_irq_info); i++) {
  91
  92                irq = platform_get_irq_byname(pdev, hi65xx_irq_info[i].name);
  93                if (irq < 0) {
  94                        error = irq;
  95                        dev_err(dev, "couldn't get irq %s: %d\n",
  96                                hi65xx_irq_info[i].name, error);
  97                        return error;
  98                }
  99
 100                error = devm_request_any_context_irq(dev, irq,
 101                                                     hi65xx_irq_info[i].handler,
 102                                                     IRQF_ONESHOT,
 103                                                     hi65xx_irq_info[i].name,
 104                                                     input);
 105                if (error < 0) {
 106                        dev_err(dev, "couldn't request irq %s: %d\n",
 107                                hi65xx_irq_info[i].name, error);
 108                        return error;
 109                }
 110        }
 111
 112        error = input_register_device(input);
 113        if (error) {
 114                dev_err(dev, "failed to register input device: %d\n", error);
 115                return error;
 116        }
 117
 118        device_init_wakeup(dev, 1);
 119
 120        return 0;
 121}
 122
 123static struct platform_driver hi65xx_powerkey_driver = {
 124        .driver = {
 125                .name = "hi65xx-powerkey",
 126        },
 127        .probe = hi65xx_powerkey_probe,
 128};
 129module_platform_driver(hi65xx_powerkey_driver);
 130
 131MODULE_AUTHOR("Zhiliang Xue <xuezhiliang@huawei.com");
 132MODULE_DESCRIPTION("Hisi PMIC Power key driver");
 133MODULE_LICENSE("GPL v2");
 134