From patchwork Thu Jan 23 01:35:37 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christopher Heiny X-Patchwork-Id: 3526361 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 103CDC02DC for ; Thu, 23 Jan 2014 01:35:51 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E4A9420181 for ; Thu, 23 Jan 2014 01:35:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0A75E2017E for ; Thu, 23 Jan 2014 01:35:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752516AbaAWBfq (ORCPT ); Wed, 22 Jan 2014 20:35:46 -0500 Received: from us-mx2.synaptics.com ([192.147.44.131]:41030 "EHLO us-mx2.synaptics.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752331AbaAWBfq (ORCPT ); Wed, 22 Jan 2014 20:35:46 -0500 Received: from unknown (HELO securemail.synaptics.com) ([172.20.21.135]) by us-mx2.synaptics.com with ESMTP; 22 Jan 2014 17:35:40 -0800 Received: from USW-OWA1.synaptics-inc.local ([10.20.24.16]) by securemail.synaptics.com (PGP Universal service); Wed, 22 Jan 2014 17:24:17 -0800 X-PGP-Universal: processed; by securemail.synaptics.com on Wed, 22 Jan 2014 17:24:17 -0800 Received: from brontomerus.synaptics.com (10.3.20.103) by USW-OWA1.synaptics-inc.local (10.20.24.15) with Microsoft SMTP Server (TLS) id 14.3.123.3; Wed, 22 Jan 2014 17:35:48 -0800 From: Christopher Heiny To: Dmitry Torokhov CC: Linux Input , Christopher Heiny , Andrew Duggan , Vincent Huang , Vivian Ly , Daniel Rosenberg , Jean Delvare , Joerie de Gram , Linus Walleij , Benjamin Tissoires Subject: [PATCH v2] input: synaptics-rmi4 - Count IRQs before creating functions; save F01 container. Date: Wed, 22 Jan 2014 17:35:37 -0800 Message-ID: <1390440937-14856-1-git-send-email-cheiny@synaptics.com> X-Mailer: git-send-email 1.8.3.1 MIME-Version: 1.0 X-Originating-IP: [10.3.20.103] X-Brightmail-Tracker: AAAAAQAAAWE= Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-7.5 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham 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 Because creating a function can trigger events that result in the IRQ related storage being accessed, we need to count the IRQs and allocate their storage before the functions are created, rather than counting them as the functions are created and allocating them afterwards. Since we know the number of IRQs already, we can allocate the mask at function creation time, rather than in a post-creation loop. Also, the F01 function_container is needed elsewhere, so we need to save it here. In order to keep the IRQ count logic sane in bootloader mode, we move the check for bootloader mode from F01 initialization to the IRQ counting routine. Signed-off-by: Christopher Heiny Cc: Dmitry Torokhov Cc: Benjamin Tissoires --- drivers/input/rmi4/rmi_driver.c | 122 ++++++++++++++++++++++++++++++---------- drivers/input/rmi4/rmi_driver.h | 1 - drivers/input/rmi4/rmi_f01.c | 11 +--- 3 files changed, 92 insertions(+), 42 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index ce0520c..5d338ef 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -560,10 +560,19 @@ static int create_function(struct rmi_device *rmi_dev, void *clbk_ctx, rmi_driver_copy_pdt_to_fd(pdt, &fn->fd, page_start); + error = rmi_driver_irq_get_mask(rmi_dev, fn); + if (error < 0) { + dev_err(dev, "%s: Failed to create irq_mask for F%02X.\n", + __func__, pdt->function_number); + return error; + } + error = rmi_register_function(fn); if (error) goto err_free_mem; + if (pdt->function_number == 0x01) + data->f01_container = fn; list_add_tail(&fn->node, &data->function_list); return RMI_SCAN_CONTINUE; @@ -573,6 +582,30 @@ err_free_mem: return RMI_SCAN_ERROR; } +/* Indicates that flash programming is enabled (bootloader mode). */ +#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40)) + +/* + * Given the PDT entry for F01, read the device status register to determine + * if we're stuck in bootloader mode or not. + * + */ +static int check_bootloader_mode(struct rmi_device *rmi_dev, struct pdt_entry *pdt, + u16 page_start) +{ + u8 device_status; + int retval = 0; + + retval = rmi_read(rmi_dev, pdt->data_base_addr + page_start, + &device_status); + if (retval < 0) { + dev_err(&rmi_dev->dev, "Failed to read device status.\n"); + return retval; + } + + return RMI_F01_STATUS_BOOTLOADER(device_status); +} + static int rmi_initial_reset(struct rmi_device *rmi_dev, void *clbk_ctx, struct pdt_entry *pdt_entry, int page) { @@ -599,6 +632,23 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev, return (!page) ? RMI_SCAN_CONTINUE : RMI_SCAN_ERROR; } +static int rmi_count_irqs(struct rmi_device *rmi_dev, + void * clbk_ctx, struct pdt_entry *pdt_entry, int page) +{ + struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); + + data->irq_count += pdt_entry->interrupt_source_count; + if (pdt_entry->function_number == 0x01) { + data->f01_bootloader_mode = check_bootloader_mode(rmi_dev, + pdt_entry, page); + if (data->f01_bootloader_mode) + dev_warn(&rmi_dev->dev, + "WARNING: RMI4 device is in bootloader mode!\n"); + } + + return RMI_SCAN_CONTINUE; +} + static int rmi_create_functions(struct rmi_device *rmi_dev) { struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); @@ -766,7 +816,6 @@ static int rmi_driver_probe(struct device *dev) { struct rmi_driver *rmi_driver; struct rmi_driver_data *data = NULL; - struct rmi_function *fn; struct rmi_device_platform_data *pdata; int retval = 0; struct rmi_device *rmi_dev; @@ -821,28 +870,6 @@ static int rmi_driver_probe(struct device *dev) if (retval) dev_warn(dev, "RMI initial reset failed! Continuing in spite of this.\n"); - retval = rmi_create_functions(rmi_dev); - if (retval) { - dev_err(dev, "PDT scan for %s failed.\n", pdata->sensor_name); - retval = -ENODEV; - goto err_free_data; - } - - if (!data->f01_container) { - dev_err(dev, "missing F01 container!\n"); - retval = -EINVAL; - goto err_free_data; - } - - list_for_each_entry(fn, &data->function_list, node) { - retval = rmi_driver_irq_get_mask(rmi_dev, fn); - if (retval < 0) { - dev_err(dev, "%s: Failed to create irq_mask.\n", - __func__); - goto err_free_data; - } - } - retval = rmi_read(rmi_dev, PDT_PROPERTIES_LOCATION, &data->pdt_props); if (retval < 0) { /* @@ -853,6 +880,22 @@ static int rmi_driver_probe(struct device *dev) PDT_PROPERTIES_LOCATION); } + /* + * We need to count the IRQs and allocate their storage before scanning + * the PDT and creating the function entries, because adding a new + * function can trigger events that result in the IRQ related storage + * being accessed. + */ + dev_dbg(dev, "Counting IRQs.\n"); + retval = rmi_scan_pdt(rmi_dev, NULL, rmi_count_irqs); + if (retval) { + retval = -ENODEV; + dev_err(dev, "IRQ counting for %s.\n", + pdata->sensor_name); + goto err_free_data; + } + data->num_of_irq_regs = (data->irq_count + 7) / 8; + mutex_init(&data->irq_mutex); data->irq_status = devm_kzalloc(dev, BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long), @@ -872,6 +915,28 @@ static int rmi_driver_probe(struct device *dev) goto err_free_data; } + data->irq_mask_store = devm_kzalloc(dev, + BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long), + GFP_KERNEL); + if (!data->irq_mask_store) { + dev_err(dev, "Failed to allocate irq_mask_store.\n"); + retval = -ENOMEM; + goto err_free_data; + } + + retval = rmi_create_functions(rmi_dev); + if (retval) { + retval = -ENODEV; + dev_err(dev, "Function creation failed.\n"); + goto err_free_data; + } + + if (!data->f01_container) { + dev_err(dev, "missing F01 container!\n"); + retval = -EINVAL; + goto err_free_data; + } + retval = rmi_read_block(rmi_dev, data->f01_container->fd.control_base_addr+1, data->current_irq_mask, data->num_of_irq_regs); @@ -881,14 +946,6 @@ static int rmi_driver_probe(struct device *dev) goto err_free_data; } - data->irq_mask_store = devm_kzalloc(dev, - BITS_TO_LONGS(data->irq_count)*sizeof(unsigned long), - GFP_KERNEL); - if (!data->irq_mask_store) { - dev_err(dev, "Failed to allocate mask store.\n"); - retval = -ENOMEM; - goto err_free_data; - } if (IS_ENABLED(CONFIG_PM)) { data->pm_data = pdata->pm_data; data->pre_suspend = pdata->pre_suspend; @@ -954,6 +1011,9 @@ static int rmi_driver_probe(struct device *dev) return 0; err_free_data: + rmi_free_function_list(rmi_dev); + if (gpio_is_valid(pdata->attn_gpio)) + gpio_free(pdata->attn_gpio); return retval; } diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index 2c1c63f..e5566c4 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -100,7 +100,6 @@ struct pdt_entry { #define RMI_SCAN_ERROR -1 #define RMI_SCAN_CONTINUE 0 #define RMI_SCAN_DONE 1 - int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, int (*rmi_pdt_scan_clbk)(struct rmi_device *rmi_dev, void *clbk_ctx, struct pdt_entry *entry, int page)); diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c index 628b082..c7f2360 100644 --- a/drivers/input/rmi4/rmi_f01.c +++ b/drivers/input/rmi4/rmi_f01.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 Synaptics Incorporated + * Copyright (c) 2011-2014 Synaptics Incorporated * Copyright (c) 2011 Unixphere * * This program is free software; you can redistribute it and/or modify it @@ -59,8 +59,6 @@ struct f01_basic_properties { /* Most recent device status event */ #define RMI_F01_STATUS_CODE(status) ((status) & 0x0f) -/* Indicates that flash programming is enabled (bootloader mode). */ -#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40)) /* The device has lost its configuration for some reason. */ #define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80)) @@ -358,13 +356,6 @@ static int rmi_f01_initialize(struct rmi_function *fn) goto error_exit; } - driver_data->f01_bootloader_mode = - RMI_F01_STATUS_BOOTLOADER(data->device_status); - if (driver_data->f01_bootloader_mode) - dev_warn(&rmi_dev->dev, - "WARNING: RMI4 device is in bootloader mode!\n"); - - if (RMI_F01_STATUS_UNCONFIGURED(data->device_status)) { dev_err(&fn->dev, "Device was reset during configuration process, status: %#02x!\n",