From patchwork Fri Nov 13 07:39:44 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phidias Chiang X-Patchwork-Id: 544091 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 845D3141402; Fri, 13 Nov 2015 18:40:11 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1Zx8xs-0000dP-HN; Fri, 13 Nov 2015 07:40:08 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1Zx8xd-0000WQ-68 for kernel-team@lists.ubuntu.com; Fri, 13 Nov 2015 07:39:53 +0000 Received: from 111-248-215-188.dynamic.hinet.net ([111.248.215.188] helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1Zx8xc-0002fF-SN for kernel-team@lists.ubuntu.com; Fri, 13 Nov 2015 07:39:53 +0000 From: Phidias Chiang To: kernel-team@lists.ubuntu.com Subject: [Vivid][SRU][PATCH 4/4] HID: rmi: Set F01 interrupt enable register when not set Date: Fri, 13 Nov 2015 15:39:44 +0800 Message-Id: <1447400384-19717-5-git-send-email-phidias.chiang@canonical.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1447400384-19717-1-git-send-email-phidias.chiang@canonical.com> References: <1447400384-19717-1-git-send-email-phidias.chiang@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: kernel-team-bounces@lists.ubuntu.com From: Andrew Duggan BugLink: http://bugs.launchpad.net/bugs/1515503 A firmware bug in some touchpads causes the F01 interrupt enable register to be cleared on reset. This register controls which RMI functions generate interrupts and when it is cleared, the touchpad stops reporting all data. This patch looks for the cleared F01 control register and writes the correct value based on interrupt mask computed while scanning the PDT. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=91102 Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina (cherry picked from commit 9a98b3387e7bd9af5a6495b32e07d6f25071f4ba) Signed-off-by: Phidias Chiang Reviewed-By: AceLan Kao --- drivers/hid/hid-rmi.c | 57 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index b6aa7db1..a11b22b 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -126,6 +126,8 @@ struct rmi_data { unsigned long firmware_id; u8 f01_ctrl0; + u8 interrupt_enable_mask; + bool restore_interrupt_mask; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -346,13 +348,34 @@ static void rmi_f11_process_touch(struct rmi_data *hdata, int slot, } } +static int rmi_reset_attn_mode(struct hid_device *hdev) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + + ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + if (ret) + return ret; + + if (data->restore_interrupt_mask) { + ret = rmi_write(hdev, data->f01.control_base_addr + 1, + &data->interrupt_enable_mask); + if (ret) { + hid_err(hdev, "can not write F01 control register\n"); + return ret; + } + } + + return 0; +} + static void rmi_reset_work(struct work_struct *work) { struct rmi_data *hdata = container_of(work, struct rmi_data, reset_work); /* switch the device to RMI if we receive a generic mouse report */ - rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS); + rmi_reset_attn_mode(hdata->hdev); } static inline int rmi_schedule_reset(struct hid_device *hdev) @@ -539,7 +562,7 @@ static int rmi_post_reset(struct hid_device *hdev) { int ret; - ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + ret = rmi_reset_attn_mode(hdev); if (ret) { hid_err(hdev, "can not set rmi mode\n"); return ret; @@ -558,7 +581,7 @@ static int rmi_post_reset(struct hid_device *hdev) static int rmi_post_resume(struct hid_device *hdev) { - return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + return rmi_reset_attn_mode(hdev); } #endif /* CONFIG_PM */ @@ -614,6 +637,7 @@ static void rmi_register_function(struct rmi_data *data, f->interrupt_count = pdt_entry->interrupt_source_count; f->irq_mask = rmi_gen_mask(f->interrupt_base, f->interrupt_count); + data->interrupt_enable_mask |= f->irq_mask; } } @@ -751,12 +775,35 @@ static int rmi_populate_f01(struct hid_device *hdev) data->firmware_id += info[2] * 65536; } - ret = rmi_read(hdev, data->f01.control_base_addr, &data->f01_ctrl0); + ret = rmi_read_block(hdev, data->f01.control_base_addr, info, + 2); if (ret) { - hid_err(hdev, "can not read f01 ctrl0\n"); + hid_err(hdev, "can not read f01 ctrl registers\n"); return ret; } + + data->f01_ctrl0 = info[0]; + + if (!info[1]) { + /* + * Do to a firmware bug in some touchpads the F01 interrupt + * enable control register will be cleared on reset. + * This will stop the touchpad from reporting data, so + * if F01 CTRL1 is 0 then we need to explicitly enable + * interrupts for the functions we want data for. + */ + data->restore_interrupt_mask = true; + + ret = rmi_write(hdev, data->f01.control_base_addr + 1, + &data->interrupt_enable_mask); + if (ret) { + hid_err(hdev, "can not write to control reg 1: %d.\n", + ret); + return ret; + } + } + return 0; }