From patchwork Wed Jun 1 21:27:39 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 69074 Delivered-To: patches@linaro.org Received: by 10.140.23.41 with SMTP id 38csp17160qgo; Wed, 1 Jun 2016 14:27:51 -0700 (PDT) X-Received: by 10.98.99.6 with SMTP id x6mr5239642pfb.140.1464816467119; Wed, 01 Jun 2016 14:27:47 -0700 (PDT) Return-Path: Received: from mail-pf0-x22c.google.com (mail-pf0-x22c.google.com. [2607:f8b0:400e:c00::22c]) by mx.google.com with ESMTPS id fu17si19866584pac.2.2016.06.01.14.27.47 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 01 Jun 2016 14:27:47 -0700 (PDT) Received-SPF: pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c00::22c as permitted sender) client-ip=2607:f8b0:400e:c00::22c; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c00::22c as permitted sender) smtp.mailfrom=john.stultz@linaro.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: by mail-pf0-x22c.google.com with SMTP id f144so22343155pfa.3 for ; Wed, 01 Jun 2016 14:27:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=e/r5j91vCv7W7mxYhG5AFSBkE75S6BKVAPzRMXTiPB0=; b=F44otB/ydGTEtAhNknYh3uVjNNmoNt815p5igHEilBSOaySNdK0Wr3R/uvMFRscWm4 A4rCXUwRinM2f4TG5HZ/2aaSujqCuD77uPn+XEJHkhDdpBUarTq+Q/lPHyT5kR9OxXaf IXS8IwgonV0H4y/DnQhXI0RhZMIn4XBAMPw3s= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=e/r5j91vCv7W7mxYhG5AFSBkE75S6BKVAPzRMXTiPB0=; b=FrbnbdFHR39k9/ysDndlGjDEmGJOteHD1Uu1NQE9Zx/Se79GJgDEWCdQ1t68n5LvRO bdDHcUCAwX1lbNsHaSqEwSgGG1AaDraPUBsaxxH3LNwGbrSjWdvi/YzT40SmhSSyc64A zvqL6TVa9HlRNVS3aTq11VrlqzHFgRRPcqOxXLcVa8HXlO9LQv3cMl28FSr3XExlXG/+ Y8AFTypzQHmvF/xxEBNDFE1AuT2xrdwTLqG1lF5WOkaaxCp1vJKFzI325pEMan3YTByM Pfp04fefhJxitAzL7DGoioRNQDiMuxPt2sBhFPsA4SaytN6Ix5C/x9tlQTgTpGWzcbcn oKqA== X-Gm-Message-State: ALyK8tIWiXZK507465p3PMsUPYcqoZPE/UPTb6KYb3pDJcrCxQai7FsizVuxy4z593zMywS9YbY= X-Received: by 10.66.126.147 with SMTP id my19mr478781pab.92.1464816466716; Wed, 01 Jun 2016 14:27:46 -0700 (PDT) Return-Path: Received: from localhost.localdomain (c-73-67-244-238.hsd1.or.comcast.net. [73.67.244.238]) by smtp.gmail.com with ESMTPSA id e79sm2115369pfd.20.2016.06.01.14.27.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 01 Jun 2016 14:27:46 -0700 (PDT) From: John Stultz To: lkml Cc: Jorge Ramirez-Ortiz , Dmitry Torokhov , Rob Herring , Pawel Moll , Mark Rutland , Ian Campbell , Kumar Gala , Lee Jones , Wei Xu , Guodong Xu , John Stultz Subject: [RFC][PATCH 4/5] drivers: input: powerkey for HISI 65xx SoC Date: Wed, 1 Jun 2016 14:27:39 -0700 Message-Id: <1464816460-18750-5-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1464816460-18750-1-git-send-email-john.stultz@linaro.org> References: <1464816460-18750-1-git-send-email-john.stultz@linaro.org> From: Jorge Ramirez-Ortiz 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. Cc: Dmitry Torokhov Cc: Rob Herring Cc: Pawel Moll Cc: Mark Rutland Cc: Ian Campbell Cc: Kumar Gala Cc: Lee Jones Cc: Jorge Ramirez-Ortiz Cc: Wei Xu Cc: Guodong Xu Signed-off-by: Jorge Ramirez-Ortiz [jstultz: Reworked commit message, folded in other fixes/cleanups from Jorge, and made a few small fixes and cleanups of my own] Signed-off-by: John Stultz --- drivers/input/misc/Kconfig | 8 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/hisi_powerkey.c | 228 +++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 drivers/input/misc/hisi_powerkey.c -- 1.9.1 diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 1f2337a..2e57bbd 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -796,4 +796,12 @@ config INPUT_DRV2667_HAPTICS To compile this driver as a module, choose M here: the module will be called drv2667-haptics. +config HISI_POWERKEY + tristate "Hisilicon PMIC ONKEY support" + 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 0357a08..f264777 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -75,3 +75,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o +obj-$(CONFIG_HISI_POWERKEY) += hisi_powerkey.o diff --git a/drivers/input/misc/hisi_powerkey.c b/drivers/input/misc/hisi_powerkey.c new file mode 100644 index 0000000..3a35a75 --- /dev/null +++ b/drivers/input/misc/hisi_powerkey.c @@ -0,0 +1,228 @@ +/* + * hisi_powerkey.c - Hisilicon MIC 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 above held interrupt will trigger after 4 seconds */ +#define MAX_HELD_TIME (4 * MSEC_PER_SEC) + + +typedef irqreturn_t (*hi65xx_irq_handler) (int irq, void *data); +enum { id_pressed, id_released, id_held, id_last }; +static irqreturn_t hi65xx_pkey_irq_handler(int irq, void *q); + +/* + * power key irq information + */ +static struct hi65xx_pkey_irq_info { + hi65xx_irq_handler handler; + const char *const name; + int irq; +} irq_info[id_last] = { + [id_pressed] = { + .handler = hi65xx_pkey_irq_handler, + .name = "down", + .irq = -1, + }, + [id_released] = { + .handler = hi65xx_pkey_irq_handler, + .name = "up", + .irq = -1, + }, + [id_held] = { + .handler = hi65xx_pkey_irq_handler, + .name = "hold 4s", + .irq = -1, + }, +}; + +/* + * power key events + */ +static struct key_report_pairs { + int code; + int value; +} pkey_report[id_last] = { + [id_released] = { + .code = KEY_POWER, + .value = 0 + }, + [id_pressed] = { + .code = KEY_POWER, + .value = 1 + }, + [id_held] = { + .code = KEY_RESTART, + .value = 0 + }, +}; + +struct hi65xx_priv { + struct input_dev *input; + struct wakeup_source wlock; +}; + +static inline void report_key(struct input_dev *dev, int id_action) +{ + /* + * track the state of the key held event since only ON/OFF values are + * allowed on EV_KEY types: KEY_RESTART will always toggle its value to + * guarantee that the event is passed to handlers (dispossition update). + */ + if (id_action == id_held) + pkey_report[id_held].value ^= 1; + + dev_dbg(dev->dev.parent, "received - code %d, value %d\n", + pkey_report[id_action].code, + pkey_report[id_action].value); + + input_report_key(dev, pkey_report[id_action].code, + pkey_report[id_action].value); +} + +static irqreturn_t hi65xx_pkey_irq_handler(int irq, void *q) +{ + struct hi65xx_priv *p = q; + int i, action = -1; + + for (i = 0; i < id_last; i++) + if (irq == irq_info[i].irq) + action = i; + + if (action == -1) + return IRQ_NONE; + + __pm_wakeup_event(&p->wlock, MAX_HELD_TIME); + + report_key(p->input, action); + input_sync(p->input); + + return IRQ_HANDLED; +} + +static int hi65xx_powerkey_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct hi65xx_priv *priv; + int irq, i, ret; + + if (pdev == NULL) { + dev_err(dev, "parameter error\n"); + return -EINVAL; + } + + priv = devm_kzalloc(dev, sizeof(struct hi65xx_priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->input = input_allocate_device(); + if (!priv->input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + return -ENOENT; + } + + priv->input->evbit[0] = BIT_MASK(EV_KEY); + priv->input->dev.parent = &pdev->dev; + priv->input->phys = "hisi_on/input0"; + priv->input->name = "HISI 65xx PowerOn Key"; + + for (i = 0; i < ARRAY_SIZE(pkey_report); i++) + input_set_capability(priv->input, EV_KEY, pkey_report[i].code); + + for (i = 0; i < ARRAY_SIZE(irq_info); i++) { + + irq = platform_get_irq_byname(pdev, irq_info[i].name); + if (irq < 0) { + dev_err(dev, "couldn't get irq %s\n", irq_info[i].name); + ret = irq; + goto err_irq; + } + + ret = devm_request_threaded_irq(dev, irq, NULL, + irq_info[i].handler, IRQF_ONESHOT, + irq_info[i].name, priv); + if (ret < 0) { + dev_err(dev, "couldn't get irq %s\n", irq_info[i].name); + goto err_irq; + } + + irq_info[i].irq = irq; + } + + wakeup_source_init(&priv->wlock, "hisi-powerkey"); + + ret = input_register_device(priv->input); + if (ret) { + dev_err(&pdev->dev, "failed to register input device: %d\n", + ret); + ret = -ENOENT; + goto err_register; + } + + platform_set_drvdata(pdev, priv); + + return 0; + +err_register: + wakeup_source_trash(&priv->wlock); +err_irq: + input_free_device(priv->input); + + return ret; +} + +static int hi65xx_powerkey_remove(struct platform_device *pdev) +{ + struct hi65xx_priv *priv = platform_get_drvdata(pdev); + + wakeup_source_trash(&priv->wlock); + input_unregister_device(priv->input); + + return 0; +} + +static const struct of_device_id hi65xx_powerkey_of_match[] = { + { .compatible = "hisilicon,hi6552-powerkey", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, hi65xx_powerkey_of_match); + +static struct platform_driver hi65xx_powerkey_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "hi65xx-powerkey", + .of_match_table = hi65xx_powerkey_of_match, + }, + .probe = hi65xx_powerkey_probe, + .remove = hi65xx_powerkey_remove, +}; + +module_platform_driver(hi65xx_powerkey_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Zhiliang Xue