mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
3.2 KiB
129 lines
3.2 KiB
/* |
|
* 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 <[email protected]"); |
|
MODULE_DESCRIPTION("Hisi PMIC Power key driver"); |
|
MODULE_LICENSE("GPL v2");
|
|
|