From patchwork Wed Sep 28 14:34:03 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Tissoires X-Patchwork-Id: 9353979 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 7835560757 for ; Wed, 28 Sep 2016 14:35:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6928F29620 for ; Wed, 28 Sep 2016 14:35:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 5DCE629624; Wed, 28 Sep 2016 14:35:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6723029620 for ; Wed, 28 Sep 2016 14:35:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932753AbcI1Oe0 (ORCPT ); Wed, 28 Sep 2016 10:34:26 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48134 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932700AbcI1OeO (ORCPT ); Wed, 28 Sep 2016 10:34:14 -0400 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 99BFE72D3F; Wed, 28 Sep 2016 14:34:13 +0000 (UTC) Received: from plouf.banquise.eu.com (ovpn-116-65.ams2.redhat.com [10.36.116.65]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u8SEY6bU015067; Wed, 28 Sep 2016 10:34:12 -0400 From: Benjamin Tissoires To: Dmitry Torokhov , KT Liao , Adrian Alves Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/4] Input: elan_i2c - add Host Notify support Date: Wed, 28 Sep 2016 16:34:03 +0200 Message-Id: <1475073244-23068-4-git-send-email-benjamin.tissoires@redhat.com> In-Reply-To: <1475073244-23068-1-git-send-email-benjamin.tissoires@redhat.com> References: <1475073244-23068-1-git-send-email-benjamin.tissoires@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Wed, 28 Sep 2016 14:34:13 +0000 (UTC) Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The Thinkpad series 13 uses Host Notify to report the interrupt. Add elan_smb_alert() to handle those interrupts and disable the irq handling on this case. Signed-off-by: Benjamin Tissoires --- drivers/input/mouse/elan_i2c_core.c | 100 ++++++++++++++++++++++++++++-------- 1 file changed, 78 insertions(+), 22 deletions(-) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 2de1f75..11671c7 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -96,6 +96,34 @@ struct elan_tp_data { bool baseline_ready; }; +static inline void elan_enable_irq(struct elan_tp_data *tp) +{ + if (tp->client->irq) + enable_irq(tp->client->irq); +} + +static inline void elan_disable_irq(struct elan_tp_data *tp) +{ + if (tp->client->irq) + disable_irq(tp->client->irq); +} + +static inline int elan_enable_irq_wake(struct elan_tp_data *tp) +{ + if (tp->client->irq) + return enable_irq_wake(tp->client->irq); + + return 0; +} + +static inline int elan_disable_irq_wake(struct elan_tp_data *tp) +{ + if (tp->client->irq) + return disable_irq_wake(tp->client->irq); + + return 0; +} + static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, u16 *signature_address) { @@ -457,7 +485,7 @@ static int elan_update_firmware(struct elan_tp_data *data, dev_dbg(&client->dev, "Starting firmware update....\n"); - disable_irq(client->irq); + elan_disable_irq(data); data->in_fw_update = true; retval = __elan_update_firmware(data, fw); @@ -471,7 +499,7 @@ static int elan_update_firmware(struct elan_tp_data *data, } data->in_fw_update = false; - enable_irq(client->irq); + elan_enable_irq(data); return retval; } @@ -599,7 +627,7 @@ static ssize_t calibrate_store(struct device *dev, if (retval) return retval; - disable_irq(client->irq); + elan_disable_irq(data); data->mode |= ETP_ENABLE_CALIBRATE; retval = data->ops->set_mode(client, data->mode); @@ -645,7 +673,7 @@ out_disable_calibrate: retval = error; } out: - enable_irq(client->irq); + elan_enable_irq(data); mutex_unlock(&data->sysfs_mutex); return retval ?: count; } @@ -711,7 +739,7 @@ static ssize_t acquire_store(struct device *dev, struct device_attribute *attr, if (retval) return retval; - disable_irq(client->irq); + elan_disable_irq(data); data->baseline_ready = false; @@ -753,7 +781,7 @@ out_disable_calibrate: retval = error; } out: - enable_irq(client->irq); + elan_enable_irq(data); mutex_unlock(&data->sysfs_mutex); return retval ?: count; } @@ -943,6 +971,23 @@ out: return IRQ_HANDLED; } +static void elan_smb_alert(struct i2c_client *client, + enum i2c_alert_protocol type, unsigned int data) +{ + struct elan_tp_data *tp_data = i2c_get_clientdata(client); + + if (type != I2C_PROTOCOL_SMBUS_HOST_NOTIFY) + return; + + if (!tp_data) { + dev_err(&client->dev, + "Something went wrong, driver data is NULL.\n"); + return; + } + + elan_isr(0, tp_data); +} + /* ****************************************************************** * Elan initialization functions @@ -1036,6 +1081,13 @@ static int elan_probe(struct i2c_client *client, I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { transport_ops = &elan_smbus_ops; + + if (!client->irq && + !i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_HOST_NOTIFY)) { + dev_err(dev, "no Host Notify support\n"); + return -ENODEV; + } } else { dev_err(dev, "not a supported I2C/SMBus adapter\n"); return -EIO; @@ -1115,19 +1167,22 @@ static int elan_probe(struct i2c_client *client, if (error) return error; - /* - * Systems using device tree should set up interrupt via DTS, - * the rest will use the default falling edge interrupts. - */ - irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; + if (client->irq) { + /* + * Systems using device tree should set up interrupt via DTS, + * the rest will use the default falling edge interrupts. + */ + irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, elan_isr, - irqflags | IRQF_ONESHOT, - client->name, data); - if (error) { - dev_err(&client->dev, "cannot register irq=%d\n", client->irq); - return error; + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, elan_isr, + irqflags | IRQF_ONESHOT, + client->name, data); + if (error) { + dev_err(&client->dev, "cannot register irq=%d\n", + client->irq); + return error; + } } error = sysfs_create_groups(&client->dev.kobj, elan_sysfs_groups); @@ -1179,12 +1234,12 @@ static int __maybe_unused elan_suspend(struct device *dev) if (ret) return ret; - disable_irq(client->irq); + elan_disable_irq(data); if (device_may_wakeup(dev)) { ret = elan_sleep(data); /* Enable wake from IRQ */ - data->irq_wake = (enable_irq_wake(client->irq) == 0); + data->irq_wake = (elan_enable_irq_wake(data) == 0); } else { ret = elan_disable_power(data); } @@ -1200,7 +1255,7 @@ static int __maybe_unused elan_resume(struct device *dev) int error; if (device_may_wakeup(dev) && data->irq_wake) { - disable_irq_wake(client->irq); + elan_disable_irq_wake(data); data->irq_wake = false; } @@ -1215,7 +1270,7 @@ static int __maybe_unused elan_resume(struct device *dev) dev_err(dev, "initialize when resuming failed: %d\n", error); err: - enable_irq(data->client->irq); + elan_enable_irq(data); return error; } @@ -1256,6 +1311,7 @@ static struct i2c_driver elan_driver = { }, .probe = elan_probe, .id_table = elan_id, + .alert = elan_smb_alert, }; module_i2c_driver(elan_driver);