From fcd6eb50eadd83f857eac55f99316f1789707cdb Mon Sep 17 00:00:00 2001 From: Jorge Ramirez-Ortiz Date: Wed, 22 Jun 2016 17:22:03 -0700 Subject: [PATCH] Input: add powerkey driver for HISI 65xx SoC This driver provides a input driver for the power button on the HiSi 65xx SoC for boards like HiKey. This driver was originally by Zhiliang Xue then basically rewritten by Jorge, but preserving the original module author credits. Signed-off-by: Jorge Ramirez-Ortiz [jstultz: Reworked commit message, folded in other fixes/cleanups from Jorge, implemented some larger cleanups suggested by DmitryT] Signed-off-by: John Stultz Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 9 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/hisi_powerkey.c | 142 +++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 drivers/input/misc/hisi_powerkey.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 27d6da0e354a..efb0ca871327 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -810,4 +810,13 @@ config INPUT_DRV2667_HAPTICS To compile this driver as a module, choose M here: the module will be called drv2667-haptics. +config INPUT_HISI_POWERKEY + tristate "Hisilicon PMIC ONKEY support" + depends on ARCH_HISI || COMPILE_TEST + help + Say Y to enable support for PMIC ONKEY. + + To compile this driver as a module, choose M here: the + module will be called hisi_powerkey. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 5373f493f370..6a1e5e20fc1c 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o +obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o diff --git a/drivers/input/misc/hisi_powerkey.c b/drivers/input/misc/hisi_powerkey.c new file mode 100644 index 000000000000..675539c529ce --- /dev/null +++ b/drivers/input/misc/hisi_powerkey.c @@ -0,0 +1,142 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* 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(&pdev->dev); + if (!input) { + dev_err(&pdev->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) { + error = irq; + dev_err(dev, "couldn't get irq %s: %d\n", + hi65xx_irq_info[i].name, error); + return error; + } + + 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(&pdev->dev, "failed to register input device: %d\n", + error); + return error; + } + + device_init_wakeup(&pdev->dev, 1); + + return 0; +} + +static int hi65xx_powerkey_remove(struct platform_device *pdev) +{ + device_init_wakeup(&pdev->dev, 0); + + return 0; +} + +static struct platform_driver hi65xx_powerkey_driver = { + .driver = { + .name = "hi65xx-powerkey", + }, + .probe = hi65xx_powerkey_probe, + .remove = hi65xx_powerkey_remove, +}; +module_platform_driver(hi65xx_powerkey_driver); + +MODULE_AUTHOR("Zhiliang Xue