Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <xuezhiliang@huawei.com>
then basically rewritten by Jorge, but preserving the original
module author credits.

Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
[jstultz: Reworked commit message, folded in other fixes/cleanups
from Jorge, implemented some larger cleanups suggested by DmitryT]
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Jorge Ramirez-Ortiz and committed by
Dmitry Torokhov
fcd6eb50 f695c240

+152
+9
drivers/input/misc/Kconfig
··· 810 810 To compile this driver as a module, choose M here: the 811 811 module will be called drv2667-haptics. 812 812 813 + config INPUT_HISI_POWERKEY 814 + tristate "Hisilicon PMIC ONKEY support" 815 + depends on ARCH_HISI || COMPILE_TEST 816 + help 817 + Say Y to enable support for PMIC ONKEY. 818 + 819 + To compile this driver as a module, choose M here: the 820 + module will be called hisi_powerkey. 821 + 813 822 endif
+1
drivers/input/misc/Makefile
··· 35 35 obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o 36 36 obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o 37 37 obj-$(CONFIG_INPUT_GPIO_TILT_POLLED) += gpio_tilt_polled.o 38 + obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o 38 39 obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o 39 40 obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o 40 41 obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
+142
drivers/input/misc/hisi_powerkey.c
··· 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 + 29 + static 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 + 40 + static 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 + 51 + static 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 + 63 + static 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 + 72 + static 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(&pdev->dev); 79 + if (!input) { 80 + dev_err(&pdev->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(&pdev->dev, "failed to register input device: %d\n", 115 + error); 116 + return error; 117 + } 118 + 119 + device_init_wakeup(&pdev->dev, 1); 120 + 121 + return 0; 122 + } 123 + 124 + static int hi65xx_powerkey_remove(struct platform_device *pdev) 125 + { 126 + device_init_wakeup(&pdev->dev, 0); 127 + 128 + return 0; 129 + } 130 + 131 + static struct platform_driver hi65xx_powerkey_driver = { 132 + .driver = { 133 + .name = "hi65xx-powerkey", 134 + }, 135 + .probe = hi65xx_powerkey_probe, 136 + .remove = hi65xx_powerkey_remove, 137 + }; 138 + module_platform_driver(hi65xx_powerkey_driver); 139 + 140 + MODULE_AUTHOR("Zhiliang Xue <xuezhiliang@huawei.com"); 141 + MODULE_DESCRIPTION("Hisi PMIC Power key driver"); 142 + MODULE_LICENSE("GPL v2");