From patchwork Mon Mar 10 16:24:04 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steve Twiss X-Patchwork-Id: 3804241 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id EEC8E9F369 for ; Mon, 10 Mar 2014 16:33:18 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7E7FC20260 for ; Mon, 10 Mar 2014 16:33:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 40A022022F for ; Mon, 10 Mar 2014 16:33:13 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753502AbaCJQcw (ORCPT ); Mon, 10 Mar 2014 12:32:52 -0400 Received: from mail1.bemta5.messagelabs.com ([195.245.231.152]:47124 "EHLO mail1.bemta5.messagelabs.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753290AbaCJQct (ORCPT ); Mon, 10 Mar 2014 12:32:49 -0400 Received: from [85.158.139.35:60744] by server-16.bemta-5.messagelabs.com id 60/D7-19700-E29ED135; Mon, 10 Mar 2014 16:32:46 +0000 X-Env-Sender: stwiss.opensource@diasemi.com X-Msg-Ref: server-13.tower-179.messagelabs.com!1394469134!31062966!3 X-Originating-IP: [82.210.246.133] X-StarScan-Received: X-StarScan-Version: 6.9.16; banners=-,-,- X-VirusChecked: Checked Received: (qmail 14919 invoked from network); 10 Mar 2014 16:32:23 -0000 Received: from mailrelay1.diasemi.com (HELO NB-EX-CASHUB01.diasemi.com) (82.210.246.133) by server-13.tower-179.messagelabs.com with AES128-SHA encrypted SMTP; 10 Mar 2014 16:32:23 -0000 Received: from mailrelay1.diasemi.com (10.1.17.243) by NB-EX-CASHUB01.diasemi.com (10.1.16.140) with Microsoft SMTP Server id 14.2.309.2; Mon, 10 Mar 2014 17:32:18 +0100 Received: from swsrvapps-01.diasemi.com (Not Verified[10.20.28.141]) by mailrelay1.diasemi.com with ESMTP Gateway id ; Mon, 10 Mar 2014 17:32:18 +0100 Received: (from stwiss@localhost) by swsrvapps-01.diasemi.com (8.14.3/8.14.3/Submit/Dlg) id s2AGWGVo007771; Mon, 10 Mar 2014 16:32:16 GMT X-Authentication-Warning: swsrvapps-01.diasemi.com: stwiss set sender to stwiss.opensource@diasemi.com using -f Message-ID: <9233b259a9afbaedbdf9737459ea210ec3d2d384.1394468644.git.stwiss.opensource@diasemi.com> In-Reply-To: References: From: "Opensource [Steve Twiss]" Date: Mon, 10 Mar 2014 16:24:04 +0000 Subject: [PATCH V1 2/2] input: misc: da9063: OnKey driver To: Dmitry Torokhov , Lee Jones , Samuel Ortiz CC: David Dajun Chen , LKML-INPUT , LKML-KERNEL , Mark Brown , Philipp Zabel MIME-Version: 1.0 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Opensource [Steve Twiss] Add the OnKey driver for DA9063. Signed-off-by: Opensource [Steve Twiss] --- Checks performed with linux-next/next-20140307/scripts/checkpatch.pl da9063-onkey.c total: 0 errors, 0 warnings, 209 lines checked Kconfig total: 0 errors, 11 warnings, 679 lines checked Makefile total: 0 errors, 0 warnings, 66 lines checked Hi Dmitry, Thank you for your previous response to my RFC. Here are my changes. I have implemented your suggestions. Please find my explanations below. Changes made to this driver since previous RFC V1: - Several alterations to the previous patch have been made according to the comments provided by Dmitry Torokhov in the previous RFC V1 e-mail thread, see here: http://www.spinics.net/lists/linux-input/msg30171.html - The use of booleans for boolean data (true/false); - The addition of an extra input_sync() in between the two calls to input_report_key(KEY_SLEEP); - The removal of call to dev_err() because it was unnecessary; - A fix for the race condition during driver remove() function: "nothing stops IRQ from firing again and rescheduling the work item". Also, the addition of a work cancelling function during the error path of the driver probe() after the interrupt has been registered. The error path of the probe() function has been refactored slightly using goto statements to make things clearer. This fix also required a change to the way the interrupt was registered: probe() is now using request_threaded_irq() instead of the devm_ equivalent so that an explicit call to free_irq() can be done before any calls to cancel_delayed_work_sync() are made; - A clarification to the way the da9063_poll_on() function should handle the I2C failure error case. The key report for KEY_POWER is now only made if there has been a fully a successful update to the DA9063_NONKEY bit in the IRQ mask. Otherwise it will continue to re-poll until the onkey's IRQ mask has been modified successfully. Dependencies: This driver makes use of the name field "ONKEY" as part of the function call: platform_get_irq_byname(); This driver is therefore dependent on this change to the name field in the properties of the the OnKey IORESOURCE_IRQ resource structure (part of the mfd_cell Onkey resource inside da9063-core.c). This change comes as part of this patch set. This patch applies against kernel version linux-next next-20140307 Regards, Steve Twiss, Dialog Semiconductor Ltd. drivers/input/misc/Kconfig | 10 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/da9063-onkey.c | 209 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 drivers/input/misc/da9063-onkey.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 762e6d2..3deb008 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -522,6 +522,16 @@ config INPUT_DA9055_ONKEY To compile this driver as a module, choose M here: the module will be called da9055_onkey. +config INPUT_DA9063_ONKEY + tristate "Dialog DA9063 OnKey" + depends on MFD_DA9063 + help + Support the ONKEY of Dialog DA9063 Power Management IC as an + input device reporting power button statue. + + To compile this driver as a module, choose M here: the module + will be called da9063-onkey. + config INPUT_DM355EVM tristate "TI DaVinci DM355 EVM Keypad and IR Remote" depends on MFD_DM355EVM_MSP diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index cda71fc..f40caa7 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o +obj-$(CONFIG_INPUT_DA9063_ONKEY) += da9063-onkey.o obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o obj-$(CONFIG_INPUT_GPIO_BEEPER) += gpio-beeper.o diff --git a/drivers/input/misc/da9063-onkey.c b/drivers/input/misc/da9063-onkey.c new file mode 100644 index 0000000..ce08954 --- /dev/null +++ b/drivers/input/misc/da9063-onkey.c @@ -0,0 +1,209 @@ +/* da9063-onkey.c - Onkey device driver for DA9063 + * Copyright (C) 2013 Dialog Semiconductor Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct da9063_onkey { + struct da9063 *hw; + struct delayed_work work; + struct input_dev *input; + int irq; + bool key_power; +}; + +static void da9063_poll_on(struct work_struct *work) +{ + struct da9063_onkey *onkey = container_of(work, struct da9063_onkey, + work.work); + unsigned int val; + bool poll = true; + int ret; + + /* poll to see when the pin is released */ + ret = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val); + if (ret < 0) { + dev_err(&onkey->input->dev, + "Failed to read ON status: %d\n", ret); + goto err_poll; + } + + if (!(val & DA9063_NONKEY)) { + ret = regmap_update_bits(onkey->hw->regmap, + DA9063_REG_CONTROL_B, + DA9063_NONKEY_LOCK, 0); + if (ret < 0) { + dev_err(&onkey->input->dev, + "Failed to reset the Key Delay %d\n", ret); + goto err_poll; + } + + /* unmask the onkey interrupt again */ + ret = regmap_update_bits(onkey->hw->regmap, + DA9063_REG_IRQ_MASK_A, + DA9063_NONKEY, 0); + if (ret < 0) { + dev_err(&onkey->input->dev, + "Failed to unmask the onkey IRQ: %d\n", ret); + goto err_poll; + } + + input_report_key(onkey->input, KEY_POWER, 0); + input_sync(onkey->input); + + poll = false; + } + +err_poll: + if (poll) + schedule_delayed_work(&onkey->work, 50); +} + +static irqreturn_t da9063_onkey_irq_handler(int irq, void *data) +{ + struct da9063_onkey *onkey = data; + unsigned int val; + int ret; + + ret = regmap_read(onkey->hw->regmap, DA9063_REG_STATUS_A, &val); + if (onkey->key_power && (ret >= 0) && (val & DA9063_NONKEY)) { + ret = regmap_update_bits(onkey->hw->regmap, + DA9063_REG_IRQ_MASK_A, + DA9063_NONKEY, 1); + if (ret < 0) + dev_err(&onkey->input->dev, + "Failed to mask the onkey IRQ: %d\n", ret); + + input_report_key(onkey->input, KEY_POWER, 1); + input_sync(onkey->input); + + schedule_delayed_work(&onkey->work, 0); + dev_dbg(&onkey->input->dev, "KEY_POWER pressed.\n"); + } else { + input_report_key(onkey->input, KEY_SLEEP, 1); + input_sync(onkey->input); + input_report_key(onkey->input, KEY_SLEEP, 0); + input_sync(onkey->input); + dev_dbg(&onkey->input->dev, "KEY_SLEEP pressed.\n"); + } + + return IRQ_HANDLED; +} + +static int da9063_onkey_probe(struct platform_device *pdev) +{ + struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); + struct da9063_pdata *pdata = dev_get_platdata(da9063->dev); + struct da9063_onkey *onkey; + bool kp_tmp = true; + int ret = 0; + + if (pdata) + kp_tmp = pdata->key_power; + + onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey), + GFP_KERNEL); + if (!onkey) { + dev_err(&pdev->dev, "Failed to allocate memory.\n"); + ret = -ENOMEM; + goto err; + } + + INIT_DELAYED_WORK(&onkey->work, da9063_poll_on); + + onkey->input = devm_input_allocate_device(&pdev->dev); + if (!onkey->input) { + dev_err(&pdev->dev, "Failed to allocated input device.\n"); + ret = -ENOMEM; + goto err; + } + + ret = platform_get_irq_byname(pdev, "ONKEY"); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get platform IRQ.\n"); + goto err; + } + onkey->irq = ret; + + ret = request_threaded_irq(onkey->irq, NULL, + da9063_onkey_irq_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "ONKEY", onkey); + if (ret) { + dev_err(&pdev->dev, + "Failed to request input device IRQ.\n"); + goto err; + } + + onkey->hw = da9063; + onkey->key_power = kp_tmp; + onkey->input->evbit[0] = BIT_MASK(EV_KEY); + onkey->input->name = DA9063_DRVNAME_ONKEY; + onkey->input->phys = DA9063_DRVNAME_ONKEY "/input0"; + onkey->input->dev.parent = &pdev->dev; + + if (onkey->key_power) + input_set_capability(onkey->input, EV_KEY, KEY_POWER); + input_set_capability(onkey->input, EV_KEY, KEY_SLEEP); + + ret = input_register_device(onkey->input); + if (ret) { + dev_err(&pdev->dev, + "Failed to register input device.\n"); + goto err_irq; + } + + platform_set_drvdata(pdev, onkey); + return 0; + +err_irq: + free_irq(onkey->irq, onkey); + cancel_delayed_work_sync(&onkey->work); +err: + return ret; +} + +static int da9063_onkey_remove(struct platform_device *pdev) +{ + struct da9063_onkey *onkey = platform_get_drvdata(pdev); + free_irq(onkey->irq, onkey); + cancel_delayed_work_sync(&onkey->work); + input_unregister_device(onkey->input); + return 0; +} + +static struct platform_driver da9063_onkey_driver = { + .probe = da9063_onkey_probe, + .remove = da9063_onkey_remove, + .driver = { + .name = DA9063_DRVNAME_ONKEY, + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(da9063_onkey_driver); + +MODULE_AUTHOR("S Twiss "); +MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);