/* 
 | 
 * Hisilicon PMIC powerkey driver 
 | 
 * 
 | 
 * Copyright (C) 2013 Hisilicon Ltd. 
 | 
 * Copyright (C) 2015, 2016 Linaro Ltd. 
 | 
 * 
 | 
 * This file is subject to the terms and conditions of the GNU General 
 | 
 * Public License. See the file "COPYING" in the main directory of this 
 | 
 * archive for more details. 
 | 
 * 
 | 
 * 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/platform_device.h> 
 | 
#include <linux/interrupt.h> 
 | 
#include <linux/reboot.h> 
 | 
#include <linux/kernel.h> 
 | 
#include <linux/module.h> 
 | 
#include <linux/of_irq.h> 
 | 
#include <linux/input.h> 
 | 
#include <linux/slab.h> 
 | 
  
 | 
/* the held interrupt will trigger after 4 seconds */ 
 | 
#define MAX_HELD_TIME    (4 * MSEC_PER_SEC) 
 | 
  
 | 
static irqreturn_t hi65xx_power_press_isr(int irq, void *q) 
 | 
{ 
 | 
    struct input_dev *input = q; 
 | 
  
 | 
    pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); 
 | 
    input_report_key(input, KEY_POWER, 1); 
 | 
    input_sync(input); 
 | 
  
 | 
    return IRQ_HANDLED; 
 | 
} 
 | 
  
 | 
static irqreturn_t hi65xx_power_release_isr(int irq, void *q) 
 | 
{ 
 | 
    struct input_dev *input = q; 
 | 
  
 | 
    pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); 
 | 
    input_report_key(input, KEY_POWER, 0); 
 | 
    input_sync(input); 
 | 
  
 | 
    return IRQ_HANDLED; 
 | 
} 
 | 
  
 | 
static irqreturn_t hi65xx_restart_toggle_isr(int irq, void *q) 
 | 
{ 
 | 
    struct input_dev *input = q; 
 | 
    int value = test_bit(KEY_RESTART, input->key); 
 | 
  
 | 
    pm_wakeup_event(input->dev.parent, MAX_HELD_TIME); 
 | 
    input_report_key(input, KEY_RESTART, !value); 
 | 
    input_sync(input); 
 | 
  
 | 
    return IRQ_HANDLED; 
 | 
} 
 | 
  
 | 
static const struct { 
 | 
    const char *name; 
 | 
    irqreturn_t (*handler)(int irq, void *q); 
 | 
} hi65xx_irq_info[] = { 
 | 
    { "down", hi65xx_power_press_isr }, 
 | 
    { "up", hi65xx_power_release_isr }, 
 | 
    { "hold 4s", hi65xx_restart_toggle_isr }, 
 | 
}; 
 | 
  
 | 
static int hi65xx_powerkey_probe(struct platform_device *pdev) 
 | 
{ 
 | 
    struct device *dev = &pdev->dev; 
 | 
    struct input_dev *input; 
 | 
    int irq, i, error; 
 | 
  
 | 
    input = devm_input_allocate_device(dev); 
 | 
    if (!input) { 
 | 
        dev_err(dev, "failed to allocate input device\n"); 
 | 
        return -ENOMEM; 
 | 
    } 
 | 
  
 | 
    input->phys = "hisi_on/input0"; 
 | 
    input->name = "HISI 65xx PowerOn Key"; 
 | 
  
 | 
    input_set_capability(input, EV_KEY, KEY_POWER); 
 | 
    input_set_capability(input, EV_KEY, KEY_RESTART); 
 | 
  
 | 
    for (i = 0; i < ARRAY_SIZE(hi65xx_irq_info); i++) { 
 | 
  
 | 
        irq = platform_get_irq_byname(pdev, hi65xx_irq_info[i].name); 
 | 
        if (irq < 0) 
 | 
            return irq; 
 | 
  
 | 
        error = devm_request_any_context_irq(dev, irq, 
 | 
                             hi65xx_irq_info[i].handler, 
 | 
                             IRQF_ONESHOT, 
 | 
                             hi65xx_irq_info[i].name, 
 | 
                             input); 
 | 
        if (error < 0) { 
 | 
            dev_err(dev, "couldn't request irq %s: %d\n", 
 | 
                hi65xx_irq_info[i].name, error); 
 | 
            return error; 
 | 
        } 
 | 
    } 
 | 
  
 | 
    error = input_register_device(input); 
 | 
    if (error) { 
 | 
        dev_err(dev, "failed to register input device: %d\n", error); 
 | 
        return error; 
 | 
    } 
 | 
  
 | 
    device_init_wakeup(dev, 1); 
 | 
  
 | 
    return 0; 
 | 
} 
 | 
  
 | 
static struct platform_driver hi65xx_powerkey_driver = { 
 | 
    .driver = { 
 | 
        .name = "hi65xx-powerkey", 
 | 
    }, 
 | 
    .probe = hi65xx_powerkey_probe, 
 | 
}; 
 | 
module_platform_driver(hi65xx_powerkey_driver); 
 | 
  
 | 
MODULE_AUTHOR("Zhiliang Xue <xuezhiliang@huawei.com"); 
 | 
MODULE_DESCRIPTION("Hisi PMIC Power key driver"); 
 | 
MODULE_LICENSE("GPL v2"); 
 |