From patchwork Thu Mar 13 01:53:53 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christopher Heiny X-Patchwork-Id: 3821541 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 3E5C09F369 for ; Thu, 13 Mar 2014 01:54:35 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id EB0AB2020A for ; Thu, 13 Mar 2014 01:54:33 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 8044C201B6 for ; Thu, 13 Mar 2014 01:54:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752582AbaCMByT (ORCPT ); Wed, 12 Mar 2014 21:54:19 -0400 Received: from us-mx2.synaptics.com ([192.147.44.131]:54609 "EHLO us-mx2.synaptics.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752522AbaCMByJ (ORCPT ); Wed, 12 Mar 2014 21:54:09 -0400 Received: from unknown (HELO securemail.synaptics.com) ([172.20.21.135]) by us-mx2.synaptics.com with ESMTP; 12 Mar 2014 18:54:05 -0700 Received: from USW-OWA1.synaptics-inc.local ([10.20.24.16]) by securemail.synaptics.com (PGP Universal service); Wed, 12 Mar 2014 18:39:50 -0700 X-PGP-Universal: processed; by securemail.synaptics.com on Wed, 12 Mar 2014 18:39:50 -0700 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, 12 Mar 2014 18:54:04 -0700 From: Christopher Heiny To: Dmitry Torokhov CC: Linux Input , Christopher Heiny , Andrew Duggan , Vincent Huang , Vivian Ly , Daniel Rosenberg , Linus Walleij , Benjamin Tissoires , David Herrmann , Jiri Kosina Subject: [PATCH v2 02/06] input synaptics-rmi4: Add some more F01 properties Date: Wed, 12 Mar 2014 18:53:53 -0700 Message-ID: <1394675637-23853-2-git-send-email-cheiny@synaptics.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1394675637-23853-1-git-send-email-cheiny@synaptics.com> References: <1394675637-23853-1-git-send-email-cheiny@synaptics.com> MIME-Version: 1.0 X-Originating-IP: [10.3.20.103] 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=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 The firmware update code will need access to the firmware build ID and some other info. As long as we're taking the scenic route to the firmware build ID, we remember a number of other interesting settings for use by diagnostic modules. Signed-off-by: Christopher Heiny Cc: Dmitry Torokhov Cc: Benjamin Tissoires Cc: Linux Walleij Cc: David Herrmann Cc: Jiri Kosina --- drivers/input/rmi4/rmi_f01.c | 170 ++++++++++++++++++++++++++++++++++++++++--- drivers/input/rmi4/rmi_f01.h | 101 +++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 9 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_f01.c b/drivers/input/rmi4/rmi_f01.c index 41cb795..8504865 100644 --- a/drivers/input/rmi4/rmi_f01.c +++ b/drivers/input/rmi4/rmi_f01.c @@ -48,11 +48,18 @@ struct f01_data { unsigned int num_of_irq_regs; }; +#define PACKAGE_ID_BYTES 4 +#define BUILD_ID_BYTES 3 + int rmi_f01_read_properties(struct rmi_device *rmi_dev, u16 query_base_addr, struct f01_basic_properties *props) { u8 basic_query[RMI_F01_BASIC_QUERY_LEN]; + u8 info_buf[4]; int error; + int i; + u16 query_addr = query_base_addr; + u16 prod_info_addr; error = rmi_read_block(rmi_dev, query_base_addr, basic_query, sizeof(basic_query)); @@ -70,19 +77,164 @@ int rmi_f01_read_properties(struct rmi_device *rmi_dev, u16 query_base_addr, basic_query[1] & RMI_F01_QRY1_HAS_ADJ_DOZE; props->has_adjustable_doze_holdoff = basic_query[1] & RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF; + props->has_query42 = basic_query[1] & RMI_F01_QRY1_HAS_PROPS_2; + + props->productinfo = + ((basic_query[2] & RMI_F01_QRY2_PRODINFO_MASK) << 7) | + (basic_query[3] & RMI_F01_QRY2_PRODINFO_MASK); snprintf(props->dom, sizeof(props->dom), "20%02d/%02d/%02d", basic_query[5] & RMI_F01_QRY5_YEAR_MASK, basic_query[6] & RMI_F01_QRY6_MONTH_MASK, basic_query[7] & RMI_F01_QRY7_DAY_MASK); - memcpy(props->product_id, &basic_query[11], - RMI_PRODUCT_ID_LENGTH); + memcpy(props->product_id, &basic_query[11], RMI_PRODUCT_ID_LENGTH); props->product_id[RMI_PRODUCT_ID_LENGTH] = '\0'; + query_addr += 11; - props->productinfo = - ((basic_query[2] & RMI_F01_QRY2_PRODINFO_MASK) << 7) | - (basic_query[3] & RMI_F01_QRY2_PRODINFO_MASK); + + error = rmi_read_block(rmi_dev, query_addr, props->product_id, + RMI_PRODUCT_ID_LENGTH); + if (error < 0) { + dev_err(&rmi_dev->dev, "Failed to read product ID.\n"); + return error; + } + props->product_id[RMI_PRODUCT_ID_LENGTH] = '\0'; + + /* We'll come back and use this later, depending on some other query + * bits. + */ + prod_info_addr = query_addr + 6; + + query_addr += RMI_PRODUCT_ID_LENGTH; + if (props->has_lts) { + error = rmi_read(rmi_dev, query_addr, info_buf); + if (error < 0) { + dev_err(&rmi_dev->dev, "Failed to read LTS info.\n"); + return error; + } + props->slave_asic_rows = info_buf[0] & + RMI_F01_QRY21_SLAVE_ROWS_MASK; + props->slave_asic_columns = (info_buf[1] & + RMI_F01_QRY21_SLAVE_COLUMNS_MASK) >> 3; + query_addr++; + } + + if (props->has_sensor_id) { + error = rmi_read(rmi_dev, query_addr, &props->sensor_id); + if (error < 0) { + dev_err(&rmi_dev->dev, "Failed to read sensor ID.\n"); + return error; + } + query_addr++; + } + + /* Maybe skip a block of undefined LTS registers. */ + if (props->has_lts) + query_addr += RMI_F01_LTS_RESERVED_SIZE; + + if (props->has_query42) { + error = rmi_read(rmi_dev, query_addr, info_buf); + if (error < 0) { + dev_err(&rmi_dev->dev, "Failed to read additional properties.\n"); + return error; + } + props->has_ds4_queries = info_buf[0] & + RMI_F01_QRY42_DS4_QUERIES; + props->has_multi_physical = info_buf[0] & + RMI_F01_QRY42_MULTI_PHYS; + props->has_guest = info_buf[0] & RMI_F01_QRY42_GUEST; + props->has_swr = info_buf[0] & RMI_F01_QRY42_SWR; + props->has_nominal_report_rate = info_buf[0] & + RMI_F01_QRY42_NOMINAL_REPORT; + props->has_recalibration_interval = info_buf[0] & + RMI_F01_QRY42_RECAL_INTERVAL; + query_addr++; + } + + if (props->has_ds4_queries) { + error = rmi_read(rmi_dev, query_addr, &props->ds4_query_length); + if (error < 0) { + dev_err(&rmi_dev->dev, "Failed to read DS4 query length size.\n"); + return error; + } + query_addr++; + } + + for (i = 1; i <= props->ds4_query_length; i++) { + u8 val; + error = rmi_read(rmi_dev, query_addr, &val); + query_addr++; + if (error < 0) { + dev_err(&rmi_dev->dev, "Failed to read F01_RMI_QUERY43.%02d, code: %d.\n", + i, error); + continue; + } + switch (i) { + case 1: + props->has_package_id_query = val & + RMI_F01_QRY43_01_PACKAGE_ID; + props->has_build_id_query = val & + RMI_F01_QRY43_01_BUILD_ID; + props->has_reset_query = val & RMI_F01_QRY43_01_RESET; + props->has_maskrev_query = val & + RMI_F01_QRY43_01_PACKAGE_ID; + break; + case 2: + props->has_i2c_control = val & RMI_F01_QRY43_02_I2C_CTL; + props->has_spi_control = val & RMI_F01_QRY43_02_SPI_CTL; + props->has_attn_control = val & + RMI_F01_QRY43_02_ATTN_CTL; + props->has_win8_vendor_info = val & + RMI_F01_QRY43_02_WIN8; + props->has_timestamp = val & RMI_F01_QRY43_02_TIMESTAMP; + break; + case 3: + props->has_tool_id_query = val & + RMI_F01_QRY43_03_TOOL_ID; + props->has_fw_revision_query = val & + RMI_F01_QRY43_03_FW_REVISION; + break; + default: + dev_warn(&rmi_dev->dev, "No handling for F01_RMI_QUERY43.%02d.\n", + i); + } + } + + /* If present, the ASIC package ID registers are overlaid on the + * product ID. Go back to the right address (saved previously) and + * read them. + */ + if (props->has_package_id_query) { + error = rmi_read_block(rmi_dev, prod_info_addr, info_buf, + PACKAGE_ID_BYTES); + if (error < 0) + dev_warn(&rmi_dev->dev, "Failed to read package ID.\n"); + else { + u16 *val = (u16 *)info_buf; + props->package_id = le16_to_cpu(*val); + val = (u16 *)(info_buf + 2); + props->package_rev = le16_to_cpu(*val); + } + } + prod_info_addr++; + + /* The firmware build id (if present) is similarly overlaid on product + * ID registers. Go back again and read that data. + */ + if (props->has_build_id_query) { + error = rmi_read_block(rmi_dev, prod_info_addr, info_buf, + BUILD_ID_BYTES); + if (error < 0) + dev_warn(&rmi_dev->dev, "Failed to read FW build ID.\n"); + else { + u16 *val = (u16 *)info_buf; + props->build_id = le16_to_cpu(*val); + props->build_id += info_buf[2] * 65536; + dev_info(&rmi_dev->dev, "FW build ID: %#08x (%u).\n", + props->build_id, props->build_id); + } + } return 0; } @@ -164,10 +316,10 @@ static int rmi_f01_probe(struct rmi_function *fn) dev_err(&fn->dev, "Failed to read F01 properties.\n"); return error; } - - dev_info(&fn->dev, "found RMI device, manufacturer: %s, product: %s\n", - f01->properties.manufacturer_id == 1 ? "Synaptics" : "unknown", - f01->properties.product_id); + dev_info(&fn->dev, "found RMI device, manufacturer: %s, product: %s, fw build: %d.\n", + f01->properties.manufacturer_id == 1 ? + "Synaptics" : "unknown", + f01->properties.product_id, f01->properties.build_id); /* Advance to interrupt control registers, then skip over them. */ ctrl_base_addr++; diff --git a/drivers/input/rmi4/rmi_f01.h b/drivers/input/rmi4/rmi_f01.h index 9e5cc2b..af82fb7 100644 --- a/drivers/input/rmi4/rmi_f01.h +++ b/drivers/input/rmi4/rmi_f01.h @@ -21,6 +21,9 @@ /* Force a firmware reset of the sensor */ #define RMI_F01_CMD_DEVICE_RESET 1 +#define RMI_F01_DEFAULT_RESET_DELAY_MS 100 + +#define F01_SERIALIZATION_SIZE 7 /* Various F01_RMI_QueryX bits */ @@ -41,20 +44,118 @@ #define RMI_F01_BASIC_QUERY_LEN 21 /* From Query 00 through 20 */ +#define RMI_F01_QRY21_SLAVE_ROWS_MASK 0x07 +#define RMI_F01_QRY21_SLAVE_COLUMNS_MASK 0x38 + +#define RMI_F01_LTS_RESERVED_SIZE 19 + +#define RMI_F01_QRY42_DS4_QUERIES (1 << 0) +#define RMI_F01_QRY42_MULTI_PHYS (1 << 1) +#define RMI_F01_QRY42_GUEST (1 << 2) +#define RMI_F01_QRY42_SWR (1 << 3) +#define RMI_F01_QRY42_NOMINAL_REPORT (1 << 4) +#define RMI_F01_QRY42_RECAL_INTERVAL (1 << 5) + +#define RMI_F01_QRY43_01_PACKAGE_ID (1 << 0) +#define RMI_F01_QRY43_01_BUILD_ID (1 << 1) +#define RMI_F01_QRY43_01_RESET (1 << 2) +#define RMI_F01_QRY43_01_MASK_REV (1 << 3) + +#define RMI_F01_QRY43_02_I2C_CTL (1 << 0) +#define RMI_F01_QRY43_02_SPI_CTL (1 << 1) +#define RMI_F01_QRY43_02_ATTN_CTL (1 << 2) +#define RMI_F01_QRY43_02_WIN8 (1 << 3) +#define RMI_F01_QRY43_02_TIMESTAMP (1 << 4) + +#define RMI_F01_QRY43_03_TOOL_ID (1 << 0) +#define RMI_F01_QRY43_03_FW_REVISION (1 << 1) + +#define RMI_F01_QRY44_RST_ENABLED (1 << 0) +#define RMI_F01_QRY44_RST_POLARITY (1 << 1) +#define RMI_F01_QRY44_PULLUP_ENABLED (1 << 2) +#define RMI_F01_QRY44_RST_PIN_MASK 0xF0 + +#define RMI_TOOL_ID_LENGTH 16 +#define RMI_FW_REVISION_LENGTH 16 + struct f01_basic_properties { u8 manufacturer_id; bool has_lts; + bool has_sensor_id; bool has_adjustable_doze; bool has_adjustable_doze_holdoff; + bool has_query42; char dom[11]; /* YYYY/MM/DD + '\0' */ u8 product_id[RMI_PRODUCT_ID_LENGTH + 1]; u16 productinfo; + u16 package_id; + u16 package_rev; + u32 build_id; + + /* These are meaningful only if has_lts is true. */ + u8 slave_asic_rows; + u8 slave_asic_columns; + + /* This is meaningful only if has_sensor_id is true. */ + u8 sensor_id; + + /* These are meaningful only if has_query42 is true. */ + bool has_ds4_queries; + bool has_multi_physical; + bool has_guest; + bool has_swr; + bool has_nominal_report_rate; + bool has_recalibration_interval; + + /* Tells how many of the Query43.xx registers are present. + */ + u8 ds4_query_length; + + /* Query 43.1 */ + bool has_package_id_query; + bool has_build_id_query; + bool has_reset_query; + bool has_maskrev_query; + + /* Query 43.2 */ + bool has_i2c_control; + bool has_spi_control; + bool has_attn_control; + bool has_win8_vendor_info; + bool has_timestamp; + + /* Query 43.3 */ + bool has_tool_id_query; + bool has_fw_revision_query; + + /* Query 44 */ + bool reset_enabled; + bool reset_polarity; + bool pullup_enabled; + u8 reset_pin; + + /* Query 45 */ + char tool_id[RMI_TOOL_ID_LENGTH + 1]; + + /* Query 46 */ + char fw_revision[RMI_FW_REVISION_LENGTH + 1]; }; + +/** Read the F01 query registers and populate the basic_properties structure. + * @rmi_dev - the device to be queries. + * @query_base_addr - address of the start of the query registers. + * @props - pointer to the structure to be filled in. + */ +int rmi_f01_read_properties(struct rmi_device *rmi_dev, u16 query_base_addr, + struct f01_basic_properties *props); + /* F01 device status bits */ /* 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))