input synaptics-rmi4: Split F01 definitions into header file
Subsystems (2)
PATCH v2 1/6 input synaptics-rmi4: Split F01 definitions into header file
Creates rmi_f01.h for use by the firmware update code.
---
drivers/input/rmi4/rmi_f01.c | 96 ++----------------------------------- drivers/input/rmi4/rmi_f01.h | 110 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 92 deletions(-)
drivers/input/rmi4/rmi_f01.c +4 -92
@@ -13,95 +13,7 @@#include <linux/slab.h> #include <linux/uaccess.h> #include "rmi_driver.h" - -#define RMI_PRODUCT_ID_LENGTH 10 -#define RMI_PRODUCT_INFO_LENGTH 2 - -#define RMI_DATE_CODE_LENGTH 3 - -#define PRODUCT_ID_OFFSET 0x10 -#define PRODUCT_INFO_OFFSET 0x1E - - -/* Force a firmware reset of the sensor */ -#define RMI_F01_CMD_DEVICE_RESET 1 - -/* Various F01_RMI_QueryX bits */ - -#define RMI_F01_QRY1_CUSTOM_MAP (1 << 0) -#define RMI_F01_QRY1_NON_COMPLIANT (1 << 1) -#define RMI_F01_QRY1_HAS_LTS (1 << 2) -#define RMI_F01_QRY1_HAS_SENSOR_ID (1 << 3) -#define RMI_F01_QRY1_HAS_CHARGER_INP (1 << 4) -#define RMI_F01_QRY1_HAS_ADJ_DOZE (1 << 5) -#define RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF (1 << 6) -#define RMI_F01_QRY1_HAS_PROPS_2 (1 << 7) - -#define RMI_F01_QRY5_YEAR_MASK 0x1f -#define RMI_F01_QRY6_MONTH_MASK 0x0f -#define RMI_F01_QRY7_DAY_MASK 0x1f - -#define RMI_F01_QRY2_PRODINFO_MASK 0x7f - -#define RMI_F01_BASIC_QUERY_LEN 21/* From Query 00 through 20 */ - -struct f01_basic_properties { -u8 manufacturer_id; -bool has_lts; -bool has_adjustable_doze; -bool has_adjustable_doze_holdoff; -char dom[11 ];/* YYYY/MM/DD + '\0' */ -u8 product_id[RMI_PRODUCT_ID_LENGTH +1 ]; -u16 productinfo; -}; - -/* F01 device status bits */ - -/* Most recent device status event */ -#define RMI_F01_STATUS_CODE (status) ((status) & 0x0f) -/* The device has lost its configuration for some reason. */ -#define RMI_F01_STATUS_UNCONFIGURED (status) (!!((status) & 0x80)) - -/* Control register bits */ - -/* -* Sleep mode controls power management on the device and affects all -* functions of the device. -*/ -#define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03 - -#define RMI_SLEEP_MODE_NORMAL 0x00 -#define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01 -#define RMI_SLEEP_MODE_RESERVED0 0x02 -#define RMI_SLEEP_MODE_RESERVED1 0x03 - -#define RMI_IS_VALID_SLEEPMODE (mode) \ - (mode >= RMI_SLEEP_MODE_NORMAL && mode <= RMI_SLEEP_MODE_RESERVED1) - -/* -* This bit disables whatever sleep mode may be selected by the sleep_mode -* field and forces the device to run at full power without sleeping. -*/ -#define RMI_F01_CRTL0_NOSLEEP_BIT (1 << 2) - -/* -* When this bit is set, the touch controller employs a noise-filtering -* algorithm designed for use with a connected battery charger. -*/ -#define RMI_F01_CRTL0_CHARGER_BIT (1 << 5) - -/* -* Sets the report rate for the device. The effect of this setting is -* highly product dependent. Check the spec sheet for your particular -* touch sensor. -*/ -#define RMI_F01_CRTL0_REPORTRATE_BIT (1 << 6) - -/* -* Written by the host as an indicator that the device has been -* successfully configured. -*/ -#define RMI_F01_CRTL0_CONFIGURED_BIT (1 << 7) +#include "rmi_f01.h" /** * @ctrl0 - see the bit definitions above.
@@ -136,8 +48,7 @@ struct f01_data {unsigned int num_of_irq_regs; }; -static int rmi_f01_read_properties (struct rmi_device *rmi_dev, -u16 query_base_addr, +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 ];
@@ -180,7 +91,8 @@ static int rmi_f01_probe(struct rmi_function *fn) {struct rmi_device *rmi_dev = fn->rmi_dev;struct rmi_driver_data *driver_data =dev_get_drvdata (&rmi_dev->dev); -const struct rmi_device_platform_data *pdata =rmi_get_platform_data (rmi_dev); +const struct rmi_device_platform_data *pdata = +rmi_get_platform_data (rmi_dev);struct f01_data *f01;int error;u16 ctrl_base_addr = fn->fd.control_base_addr;
drivers/input/rmi4/rmi_f01.h new file +110 -0
110 lines not on this page · raw message
PATCH v2 2/6 input synaptics-rmi4: Add some more F01 properties
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.
---
drivers/input/rmi4/rmi_f01.c | 170 ++++++++++++++++++++++++++++++++++++++++--- drivers/input/rmi4/rmi_f01.h | 101 +++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 9 deletions(-)
drivers/input/rmi4/rmi_f01.c +161 -9
@@ -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++;
drivers/input/rmi4/rmi_f01.h +101 -0
127 lines not on this page · raw message
PATCH v2 3/6 input synaptics-rmi4: rmi_f01 - Fix a comment, add a diagnostic message.
In reply to Christopher HeinyIn debugging certain touch sensor failures, it's useful to know whether the device is stuck in bootloader, so print a message to that effect.
Also, point to the actual location of the defs for the F01 CTRL0 bitfields.
---
drivers/input/rmi4/rmi_f01.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/input/rmi4/rmi_f01.c +8 -1
@@ -16,7 +16,7 @@#include "rmi_f01.h" /** -* @ctrl0 - see the bit definitions above. +* @ctrl0 - see the bit definitions in rmi_f01.h. * @doze_interval - controls the interval between checks for finger presence * when the touch sensor is in doze mode, in units of 10ms. * @wakeup_threshold - controls the capacitance threshold at which the touch
@@ -415,6 +415,13 @@ static int rmi_f01_probe(struct rmi_function *fn)return error; } + driver_data->f01_bootloader_mode = +RMI_F01_STATUS_BOOTLOADER (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 (device_status)) { dev_err(&fn->dev, "Device was reset during configuration process, status: %#02x!\n",
PATCH v2 4/6 input synaptics-rmi4: rmi_driver - Export some symbols and functions
In reply to Christopher HeinyFirmware update functionality will need to unload the existing functions and rescan the PDT before starting the update process; then reload the functions afterwards.
---
drivers/input/rmi4/rmi_driver.c | 165 ++++++++++++++++++++++------------------ drivers/input/rmi4/rmi_driver.h | 22 +++--- 2 files changed, 101 insertions(+), 86 deletions(-)
drivers/input/rmi4/rmi_driver.c +89 -76
@@ -31,14 +31,20 @@#include <uapi/linux/input.h> #include "rmi_bus.h" #include "rmi_driver.h" +#include "rmi_f01.h" #define HAS_NONSTANDARD_PDT_MASK 0x40#define RMI4_MAX_PAGE 0xff#define RMI4_PAGE_SIZE 0x100#define RMI4_PAGE_MASK 0xFF00 -#define RMI_DEVICE_RESET_CMD 0x01 -#define DEFAULT_RESET_DELAY_MS 100 +#define RMI_PDT_ENTRY_SIZE 6 +#define RMI_PDT_FUNCTION_VERSION_MASK 0x60 +#define RMI_PDT_INT_SOURCE_COUNT_MASK 0x07 + +#define PDT_START_SCAN_LOCATION 0x00e9 +#define PDT_END_SCAN_LOCATION 0x0005 +#define RMI4_END_OF_PDT (id) ((id) == 0x00 || (id) == 0xff)#define DEFAULT_POLL_INTERVAL_MS 13
@@ -174,7 +180,7 @@ static int enable_sensor(struct rmi_device *rmi_dev)return process_interrupt_requests (rmi_dev); } -static void rmi_free_function_list (struct rmi_device *rmi_dev) +void rmi_free_function_list (struct rmi_device *rmi_dev) {struct rmi_function *fn, *tmp;struct rmi_driver_data *data =dev_get_drvdata (&rmi_dev->dev);
@@ -435,8 +441,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev)return 0 ; } -int rmi_read_pdt_entry (struct rmi_device *rmi_dev,struct pdt_entry *entry, -u16 pdt_address) +static int rmi_read_pdt_entry (struct rmi_device *rmi_dev, +struct pdt_entry *entry,u16 pdt_address) {u8 buf[RMI_PDT_ENTRY_SIZE ];int error;
@@ -459,7 +465,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,return 0 ; } -EXPORT_SYMBOL_GPL (rmi_read_pdt_entry);static void rmi_driver_copy_pdt_to_fd (const struct pdt_entry *pdt,struct rmi_function_descriptor *fd)
@@ -473,9 +478,6 @@ static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt, fd->function_version = pdt->function_version; } -#define RMI_SCAN_CONTINUE 0 -#define RMI_SCAN_DONE 1 - static int rmi_scan_pdt_page(struct rmi_device *rmi_dev, int page, void *ctx,
@@ -508,10 +510,9 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,return data->f01_bootloader_mode ?RMI_SCAN_DONE :RMI_SCAN_CONTINUE ; } -static int rmi_scan_pdt (struct rmi_device *rmi_dev,void *ctx, -int (*callback)(struct rmi_device *rmi_dev, -void *ctx, -const struct pdt_entry *entry)) +int rmi_scan_pdt (struct rmi_device *rmi_dev,void *ctx, +int (*callback)(struct rmi_device *rmi_dev, +void *ctx,const struct pdt_entry *entry)) {int page;int retval =RMI_SCAN_DONE ;
@@ -525,16 +526,13 @@ static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,return retval <0 ? retval :0 ; } -/* 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 rmi_check_bootloader_mode (struct rmi_device *rmi_dev, -const struct pdt_entry *pdt) +int rmi_check_bootloader_mode (struct rmi_device *rmi_dev, +const struct pdt_entry *pdt) {int error;u8 device_status;
@@ -575,7 +573,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,if (pdt->function_number ==0x01 ) {u16 cmd_addr = pdt->page_start + pdt->command_base_addr; -u8 cmd_buf =RMI_DEVICE_RESET_CMD ; +u8 cmd_buf =RMI_F01_CMD_DEVICE_RESET ;const struct rmi_device_platform_data *pdata =rmi_get_platform_data (rmi_dev);
@@ -586,7 +584,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,return error; } -mdelay (pdata->reset_delay_ms ?:DEFAULT_RESET_DELAY_MS ); +mdelay (pdata->reset_delay_ms ?:RMI_F01_DEFAULT_RESET_DELAY_MS );return RMI_SCAN_DONE ; }
@@ -728,15 +726,80 @@ static int rmi_driver_remove(struct device *dev)return 0 ; } +int rmi_driver_detect_functions (struct rmi_device *rmi_dev) +{ +int error; +int irq_count; +struct rmi_driver_data *data =dev_get_drvdata (&rmi_dev->dev); +void *irq_memory; +size_t size; + +/* +* 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 (&rmi_dev->dev,"Counting IRQs.\n" ); + irq_count =0 ; + error =rmi_scan_pdt (rmi_dev, &irq_count, rmi_count_irqs); +if (error) { + error = -ENODEV ; +dev_err (&rmi_dev->dev,"IRQ counting failed with code %d.\n" , + error); + goto err_free_mem; + } + data->irq_count = irq_count; + data->num_of_irq_regs = (data->irq_count +7 ) /8 ; + + size =BITS_TO_LONGS (data->irq_count) *sizeof (unsigned long ); + irq_memory =kzalloc (size *4 ,GFP_KERNEL ); +if (!irq_memory) { +dev_err (&rmi_dev->dev,"Failed to allocate memory for irq masks.\n" ); + goto err_free_mem; + } +kfree (data->irq_status);/* free the memory if it's allocated already */ + data->irq_status = irq_memory + size *0 ; + data->fn_irq_bits = irq_memory + size *1 ; + data->current_irq_mask = irq_memory + size *2 ; + data->new_irq_mask = irq_memory + size *3 ; + + irq_count =0 ; +dev_dbg (&rmi_dev->dev,"Creating functions." ); + error =rmi_scan_pdt (rmi_dev, &irq_count, rmi_create_function); +if (error <0 ) { +dev_err (&rmi_dev->dev,"Function creation failed with code %d.\n" , + error); + goto err_destroy_functions; + } +if (!data->f01_container) { +dev_err (&rmi_dev->dev,"missing F01 container!\n" ); + error = -EINVAL ; + goto err_destroy_functions; + } + error =rmi_read_block (rmi_dev, + data->f01_container->fd.control_base_addr+1 , + data->current_irq_mask, data->num_of_irq_regs); +if (error) { +dev_err (&rmi_dev->dev,"%s: Failed to read current IRQ mask.\n" , + __func__); + goto err_destroy_functions; + } +return 0 ; + +err_destroy_functions: +rmi_free_function_list (rmi_dev); +kfree (irq_memory); +err_free_mem: +return error; +} +static int rmi_driver_probe (struct device *dev) {struct rmi_driver *rmi_driver;struct rmi_driver_data *data;const struct rmi_device_platform_data *pdata;struct rmi_device *rmi_dev; -size_t size; -void *irq_memory; -int irq_count;int retval;dev_dbg (dev,"%s: Starting probe.\n" , __func__);
@@ -796,59 +859,11 @@ static int rmi_driver_probe(struct device *dev)dev_warn (dev,"Could not read PDT properties from %#06x (code %d). Assuming 0x00.\n" ,PDT_PROPERTIES_LOCATION , retval); } - -/* -* 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" ); - irq_count =0 ; - retval =rmi_scan_pdt (rmi_dev, &irq_count, rmi_count_irqs); -if (retval <0 ) { -dev_err (dev,"IRQ counting for %s failed with code %d.\n" , - pdata->sensor_name, retval); - goto err_free_mem; - } - data->irq_count = irq_count; - data->num_of_irq_regs = (data->irq_count +7 ) /8 ; -mutex_init (&data->irq_mutex); - size =BITS_TO_LONGS (data->irq_count) *sizeof (unsigned long ); - irq_memory =kzalloc (size *4 ,GFP_KERNEL ); -if (!irq_memory) { -dev_err (dev,"Failed to allocate memory for irq masks.\n" ); - goto err_free_mem; - } - - data->irq_status = irq_memory + size *0 ; - data->fn_irq_bits = irq_memory + size *1 ; - data->current_irq_mask = irq_memory + size *2 ; - data->new_irq_mask = irq_memory + size *3 ; - - irq_count =0 ; -dev_dbg (dev,"Creating functions." ); - retval =rmi_scan_pdt (rmi_dev, &irq_count, rmi_create_function); -if (retval <0 ) { -dev_err (dev,"Function creation failed with code %d.\n" , - retval); - goto err_destroy_functions; - } - -if (!data->f01_container) { -dev_err (dev,"Missing F01 container!\n" ); - retval = -EINVAL ; - goto err_destroy_functions; - } - - retval =rmi_read_block (rmi_dev, - data->f01_container->fd.control_base_addr +1 , - data->current_irq_mask, data->num_of_irq_regs); -if (retval <0 ) { -dev_err (dev,"%s: Failed to read current IRQ mask.\n" , - __func__); + retval =rmi_driver_detect_functions (rmi_dev); +if (retval) { +dev_err (dev,"Failed to detect functions!\n" ); goto err_destroy_functions; }
@@ -918,8 +933,6 @@ static int rmi_driver_probe(struct device *dev) err_destroy_functions:rmi_free_function_list (rmi_dev); -kfree (irq_memory); -err_free_mem:if (data->gpio_held)gpio_free (pdata->attn_gpio);kfree (data);
drivers/input/rmi4/rmi_driver.h +12 -10
@@ -84,14 +84,6 @@ struct rmi_driver_data {void *data; }; -#define RMI_PDT_ENTRY_SIZE 6 -#define RMI_PDT_FUNCTION_VERSION_MASK 0x60 -#define RMI_PDT_INT_SOURCE_COUNT_MASK 0x07 - -#define PDT_START_SCAN_LOCATION 0x00e9 -#define PDT_END_SCAN_LOCATION 0x0005 -#define RMI4_END_OF_PDT (id) ((id) == 0x00 || (id) == 0xff) -struct pdt_entry {u16 page_start;u8 query_base_addr;
@@ -103,8 +95,12 @@ struct pdt_entry {u8 function_number; }; -int rmi_read_pdt_entry (struct rmi_device *rmi_dev,struct pdt_entry *entry, -u16 pdt_address); +#define RMI_SCAN_CONTINUE 0 +#define RMI_SCAN_DONE 1 + +int rmi_scan_pdt (struct rmi_device *rmi_dev,void *ctx, +int (*callback)(struct rmi_device *rmi_dev, +void *ctx,const struct pdt_entry *entry));bool rmi_is_physical_driver (struct device_driver *);int rmi_register_physical_driver (void );
@@ -113,4 +109,10 @@ void rmi_unregister_physical_driver(void);int rmi_register_f01_handler (void );void rmi_unregister_f01_handler (void ); +int rmi_check_bootloader_mode (struct rmi_device *rmi_dev, +const struct pdt_entry *pdt); +void rmi_free_function_list (struct rmi_device *rmi_dev); +int rmi_driver_detect_functions (struct rmi_device *rmi_dev); + +#endif
PATCH v2 5/6 input synaptics-rmi4: Add firmware update support
In reply to Christopher HeinyAdd support for updating firmware on RMI4 devices with V5 bootloader.
---
The next patch in this series converts this code to use request_firmware_nowait(). We split that change off to make it easier to check differences between this and the v1 patch.
drivers/input/rmi4/Kconfig +18 -0
@@ -25,6 +25,24 @@ config RMI4_DEBUG If unsure, say N. +config RMI4_FW_UPDATE + bool "RMI4 Firmware Update" + depends on RMI4_CORE + help + Say Y here to enable in-kernel firmware update capability. + + This allows you to update an RMI4 device's firmware using the + kernel request_firmware() facility. Control is provided via + a sysfs interface. Write 1 to /sys/devices/sensorXX/update_fw + to cause an update. The image file name will be derived from + the F01 product ID value; write a different name to + .../sensorXX/fw_img_name override that. The update will only + happen if the provided image appears to be newer than the + one currently running on the RMI4 device; write 1 to + ../sensorXX/fw_force_update to override that (this might be + required for older devices that don't implement the + necessary RMI4 queries). + config RMI4_I2C tristate "RMI4 I2C Support" depends on RMI4_CORE && I2C
drivers/input/rmi4/Makefile +1 -0
@@ -1,5 +1,6 @@ obj-$(CONFIG_RMI4_CORE) += rmi_core.o rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o +rmi_core-$(CONFIG_RMI4_FW_UPDATE) += rmi_fw_update.o # Function drivers obj-$(CONFIG_RMI4_F11) += rmi_f11.o
drivers/input/rmi4/rmi_bus.c +3 -0
@@ -117,6 +117,8 @@ int rmi_register_transport_device(struct rmi_transport_dev *xport)if (error) goto err_put_device; +rmi_fw_update_init (rmi_dev); +dev_dbg (xport->dev,"%s: Registered %s as %s.\n" , __func__, pdata->sensor_name,dev_name (&rmi_dev->dev));
@@ -139,6 +141,7 @@ void rmi_unregister_transport_device(struct rmi_transport_dev *xport)struct rmi_device *rmi_dev = xport->rmi_dev;device_del (&rmi_dev->dev); +rmi_fw_update_cleanup (rmi_dev);rmi_physical_teardown_debugfs (rmi_dev);put_device (&rmi_dev->dev); }
drivers/input/rmi4/rmi_driver.c +1 -1
@@ -833,7 +833,7 @@ static int rmi_driver_probe(struct device *dev)* previous settings and force it into normal operation. * * We have to do this before actually building the PDT because -* the reflash updates (if any) might cause various registers to move +* the firmware updates (if any) might cause various registers to move * around. * * For a number of reasons, this initial reset may fail to return
drivers/input/rmi4/rmi_driver.h +16 -0
@@ -29,6 +29,8 @@#define RMI_PDT_PROPS_HAS_BSR 0x02 +struct rmi_fw_update_data ; +struct rmi_driver_data {struct list_head function_list;
@@ -81,6 +83,8 @@ struct rmi_driver_data {u8 reg_debug_size;#endif +struct rmi_fw_update_data *fw_update_data; +void *data; };
@@ -114,5 +118,17 @@ int rmi_check_bootloader_mode(struct rmi_device *rmi_dev,void rmi_free_function_list (struct rmi_device *rmi_dev);int rmi_driver_detect_functions (struct rmi_device *rmi_dev); +#ifdef CONFIG_RMI4_FW_UPDATE +void rmi_fw_update_init (struct rmi_device *rmi_dev); +void rmi_fw_update_cleanup (struct rmi_device *rmi_dev); +#else +static inline void rmi_fw_update_init (struct rmi_device *rmi_dev) +{ +} + +static inline void rmi_fw_update_cleanup (struct rmi_device *rmi_dev) +{ +} +#endif #endif
drivers/input/rmi4/rmi_fw_update.c new file +942 -0
942 lines not on this page · raw message
include/linux/rmi.h +3 -3
@@ -196,8 +196,8 @@ struct rmi_device_platform_data_spi {* * @sensor_name - this is used for various diagnostic messages. * -* @firmware_name - if specified will override default firmware name, -* for reflashing. +* @firmware_name - if specified will override default firmware image name +* used by the firmware update feature. * * @attn_gpio - the index of a GPIO that will be used to provide the ATTN * interrupt from the touch sensor.
@@ -270,7 +270,7 @@ struct rmi_device_platform_data {struct rmi_f30_gpioled_map *gpioled_map;struct rmi_button_map *f41_button_map; -#ifdef CONFIG_RMI4_FWLIB +#ifdef CONFIG_RMI4_FW_UPDATE char *firmware_name;#endif
Dmitry Torokhov
maintainerRe: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
Hi Christopher,
Quoted 1 line · Christopher Heiny
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct rmi_function_handler and does not rely on RMI core to bind itself to the device if device supports it.
By the way, isn't rmi_extract_u32() is the same as le32_to_cpup()?
Thanks.
Signature · 1 line
Dmitry
Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
Quoted 9 lines · Dmitry Torokhov
Hi Christopher,
Quoted 1 line · Christopher Heiny
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct
rmi_function_handlerand does not rely on RMI core to bind itself to the device if device supports it.
Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function standard and exposed most of the basic F34 operations via sysfs. However, we got feedback (both on LKML and offline) (a) recommending to use request_firmware, and (b) improve reflash times while (c) reducing impact on boot time, and (d) "get rid of all that sysfs crap" (paraphrased, but close to it).
So after looking at how some other drivers use request_firmware, we came up with the current approach. Switching to request_firmware definitely sped up the reflash times! Including a check to see if firmware update is required before setting up the RMI4 sensor/function structures also significantly reduced boot times.
Quoted 1 line
By the way, isn't
rmi_extract_u32()is the same asle32_to_cpup()?
Hmmm. Looks like that one escaped the sweep of roll-your-own endian fixes. I'll update it.
Chris
Dmitry Torokhov
maintainerRe: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
Quoted 20 lines · Christopher Heiny
Quoted 9 lines · Dmitry Torokhov
Hi Christopher,
Quoted 1 line · Christopher Heiny
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct
rmi_function_handlerand does not rely on RMI core to bind itself to the device if device supports it.Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function standard and exposed most of the basic F34 operations via sysfs. However, we got feedback (both on LKML and offline) (a) recommending to use
request_firmware, and (b) improve reflash times while (c) reducing impact on boot time, and (d) "get rid of all that sysfs crap" (paraphrased, but close to it).
Quoted 5 lines
So after looking at how some other drivers use
request_firmware, we came up with the current approach. Switching torequest_firmwaredefinitely sped up the reflash times! Including a check to see if firmware update is required before setting up the RMI4 sensor/function structures also significantly reduced boot times.
I am not suggesting you stop using request-firmware or introduce bazillion of new sysfs attributes. I just wondered why you have manual "binding" of F34 functionality instead of standrad RMI4 function binding, liek you do for F01, F11 and so forth.
Thanks.
Signature · 1 line
Dmitry
Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
Quoted 27 lines · Dmitry Torokhov
Quoted 20 lines · Christopher Heiny
Quoted 20 lines · Dmitry Torokhov
Quoted 9 lines
Quoted 9 lines
Hi Christopher,
Quoted 1 line · Christopher Heiny
Quoted 1 line
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct
rmi_function_handlerand does not rely on RMI core to bind itself to the device if device supports it.Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function standard and exposed most of the basic F34 operations via sysfs. However, we got feedback (both on LKML and offline) (a) recommending to use
request_firmware, and (b) improve reflash times while (c) reducing impact on boot time, and (d) "get rid of all that sysfs crap" (paraphrased, but close to it).Quoted 5 lines
Quoted 5 lines
So after looking at how some other drivers use
request_firmware, we came up with the current approach. Switching torequest_firmwaredefinitely sped up the reflash times! Including a check to see if firmware update is required before setting up the RMI4 sensor/function structures also significantly reduced boot times.
Quoted 4 lines
I am not suggesting you stop using request-firmware or introduce bazillion of new sysfs attributes. I just wondered why you have manual "binding" of F34 functionality instead of standrad RMI4 function binding, liek you do for F01, F11 and so forth.
Sorry! My answer wasn't very clear on that part, was it?
The manual binding gets the reflash (if required) done very early in the boot/probe process. This eliminates the need to set up the whole sensor + functions structure, tear it down in order to reflash, and then build it all back up again. It is felt that the time savings is significant, especially on highly featured products.
Chris
Dmitry Torokhov
maintainerRe: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
Quoted 33 lines · Christopher Heiny
Quoted 27 lines · Dmitry Torokhov
Quoted 20 lines · Christopher Heiny
Quoted 20 lines · Dmitry Torokhov
Quoted 9 lines
Quoted 9 lines
Hi Christopher,
Quoted 1 line · Christopher Heiny
Quoted 1 line
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct
rmi_function_handlerand does not rely on RMI core to bind itself to the device if device supports it.Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function standard and exposed most of the basic F34 operations via sysfs. However, we got feedback (both on LKML and offline) (a) recommending to use
request_firmware, and (b) improve reflash times while (c) reducing impact on boot time, and (d) "get rid of all that sysfs crap" (paraphrased, but close to it).Quoted 5 lines
Quoted 5 lines
So after looking at how some other drivers use
request_firmware, we came up with the current approach. Switching torequest_firmwaredefinitely sped up the reflash times! Including a check to see if firmware update is required before setting up the RMI4 sensor/function structures also significantly reduced boot times.Quoted 4 lines
I am not suggesting you stop using request-firmware or introduce bazillion of new sysfs attributes. I just wondered why you have manual "binding" of F34 functionality instead of standrad RMI4 function binding, liek you do for F01, F11 and so forth.
Quoted 7 lines
Sorry! My answer wasn't very clear on that part, was it?
The manual binding gets the reflash (if required) done very early in the boot/probe process. This eliminates the need to set up the whole sensor + functions structure, tear it down in order to reflash, and then build it all back up again. It is felt that the time savings is significant, especially on highly featured products.
I am sorry but I have hard time accepting this argument. How often do you reflash devices during normal operation and how long does it take to initialize the device compared to getting entire userspace up and running to be able to actually supply or serve flash data (even without using usermode helper to flash you need filesystem with the firmware to be mounted)?
Thanks.
Signature · 1 line
Dmitry
Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
[I sent this last Thursday, but it never showed up on the input list. I'm assuming nobody else saw it.]
Quoted 42 lines · Dmitry Torokhov
Quoted 33 lines · Christopher Heiny
Quoted 27 lines · Dmitry Torokhov
Quoted 20 lines · Christopher Heiny
Quoted 20 lines · Dmitry Torokhov
Quoted 9 lines
Quoted 9 lines
Hi Christopher,
Quoted 1 line · Christopher Heiny
Quoted 1 line
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct
rmi_function_handlerand does not rely on RMI core to bind itself to the device if device supports it.Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function standard and exposed most of the basic F34 operations via sysfs. However, we got feedback (both on LKML and offline) (a) recommending to use
request_firmware, and (b) improve reflash times while (c) reducing impact on boot time, and (d) "get rid of all that sysfs crap" (paraphrased, but close to it).Quoted 5 lines
Quoted 5 lines
So after looking at how some other drivers use
request_firmware, we came up with the current approach. Switching torequest_firmwaredefinitely sped up the reflash times! Including a check to see if firmware update is required before setting up the RMI4 sensor/function structures also significantly reduced boot times.Quoted 4 lines
I am not suggesting you stop using request-firmware or introduce bazillion of new sysfs attributes. I just wondered why you have manual "binding" of F34 functionality instead of standrad RMI4 function binding, liek you do for F01, F11 and so forth.
Quoted 7 lines
Sorry! My answer wasn't very clear on that part, was it?
The manual binding gets the reflash (if required) done very early in the boot/probe process. This eliminates the need to set up the whole sensor + functions structure, tear it down in order to reflash, and then build it all back up again. It is felt that the time savings is significant, especially on highly featured products.
Quoted 6 lines
I am sorry but I have hard time accepting this argument. How often do you reflash devices during normal operation and how long does it take to initialize the device compared to getting entire userspace up and running to be able to actually supply or serve flash data (even without using usermode helper to flash you need filesystem with the firmware to be mounted)?
That was my argument exactly, but that was the direction we were pushed.
I'd much rather implement it as we discussed offline earlier this
week. If you were to say: "I'm sorry, but this simply can't be merged as it stands." you wouldn't get any argument from me on technical grounds. There might be people who will argue about the additional calendar time it would take to restructure it, though.
Dmitry Torokhov
maintainerRe: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
Quoted 54 lines · Christopher Heiny
[I sent this last Thursday, but it never showed up on the input list. I'm assuming nobody else saw it.]
Quoted 42 lines · Dmitry Torokhov
Quoted 33 lines · Christopher Heiny
Quoted 27 lines · Dmitry Torokhov
Quoted 20 lines · Christopher Heiny
Quoted 20 lines · Dmitry Torokhov
Quoted 9 lines
Quoted 9 lines
Hi Christopher,
Quoted 1 line · Christopher Heiny
Quoted 1 line
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct
rmi_function_handlerand does not rely on RMI core to bind itself to the device if device supports it.Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function standard and exposed most of the basic F34 operations via sysfs. However, we got feedback (both on LKML and offline) (a) recommending to use
request_firmware, and (b) improve reflash times while (c) reducing impact on boot time, and (d) "get rid of all that sysfs crap" (paraphrased, but close to it).Quoted 5 lines
Quoted 5 lines
So after looking at how some other drivers use
request_firmware, we came up with the current approach. Switching torequest_firmwaredefinitely sped up the reflash times! Including a check to see if firmware update is required before setting up the RMI4 sensor/function structures also significantly reduced boot times.Quoted 4 lines
I am not suggesting you stop using request-firmware or introduce bazillion of new sysfs attributes. I just wondered why you have manual "binding" of F34 functionality instead of standrad RMI4 function binding, liek you do for F01, F11 and so forth.
Quoted 7 lines
Sorry! My answer wasn't very clear on that part, was it?
The manual binding gets the reflash (if required) done very early in the boot/probe process. This eliminates the need to set up the whole sensor + functions structure, tear it down in order to reflash, and then build it all back up again. It is felt that the time savings is significant, especially on highly featured products.
Quoted 6 lines
I am sorry but I have hard time accepting this argument. How often do you reflash devices during normal operation and how long does it take to initialize the device compared to getting entire userspace up and running to be able to actually supply or serve flash data (even without using usermode helper to flash you need filesystem with the firmware to be mounted)?
Quoted 6 lines
That was my argument exactly, but that was the direction we were pushed. I'd much rather implement it as we discussed offline earlier this week. If you were to say: "I'm sorry, but this simply can't be merged as it stands." you wouldn't get any argument from me on technical grounds. There might be people who will argue about the additional calendar time it would take to restructure it, though.
OK, then I will just say this: "I'm sorry, but this simply can't be merged as it stands."
Now, I am talking about mainline here, I am fairly certain we can resolve scheduling issues between what you currently have and what is needed in the end.
Thanks.
Signature · 1 line
Dmitry
Re: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
Quoted 62 lines · Dmitry Torokhov
Quoted 54 lines · Christopher Heiny
[I sent this last Thursday, but it never showed up on the input list. I'm assuming nobody else saw it.]
Quoted 42 lines · Dmitry Torokhov
Quoted 33 lines · Christopher Heiny
Quoted 27 lines · Dmitry Torokhov
Quoted 20 lines · Christopher Heiny
Quoted 20 lines · Dmitry Torokhov
Quoted 9 lines
Quoted 9 lines
Hi Christopher,
Quoted 1 line · Christopher Heiny
Quoted 1 line
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct
rmi_function_handlerand does not rely on RMI core to bind itself to the device if device supports it.Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function standard and exposed most of the basic F34 operations via sysfs. However, we got feedback (both on LKML and offline) (a) recommending to use
request_firmware, and (b) improve reflash times while (c) reducing impact on boot time, and (d) "get rid of all that sysfs crap" (paraphrased, but close to it).Quoted 5 lines
Quoted 5 lines
So after looking at how some other drivers use
request_firmware, we came up with the current approach. Switching torequest_firmwaredefinitely sped up the reflash times! Including a check to see if firmware update is required before setting up the RMI4 sensor/function structures also significantly reduced boot times.Quoted 4 lines
I am not suggesting you stop using request-firmware or introduce bazillion of new sysfs attributes. I just wondered why you have manual "binding" of F34 functionality instead of standrad RMI4 function binding, liek you do for F01, F11 and so forth.
Quoted 7 lines
Sorry! My answer wasn't very clear on that part, was it?
The manual binding gets the reflash (if required) done very early in the boot/probe process. This eliminates the need to set up the whole sensor + functions structure, tear it down in order to reflash, and then build it all back up again. It is felt that the time savings is significant, especially on highly featured products.
Quoted 6 lines
I am sorry but I have hard time accepting this argument. How often do you reflash devices during normal operation and how long does it take to initialize the device compared to getting entire userspace up and running to be able to actually supply or serve flash data (even without using usermode helper to flash you need filesystem with the firmware to be mounted)?
Quoted 6 lines
That was my argument exactly, but that was the direction we were pushed. I'd much rather implement it as we discussed offline earlier this week. If you were to say: "I'm sorry, but this simply can't be merged as it stands." you wouldn't get any argument from me on technical grounds. There might be people who will argue about the additional calendar time it would take to restructure it, though.
Quoted 6 lines
OK, then I will just say this: "I'm sorry, but this simply can't be merged as it stands."
Now, I am talking about mainline here, I am fairly certain we can resolve scheduling issues between what you currently have and what is needed in the end.
OK. The question on our end becomes - can we accept the current implementation as a baseline while we rework the implementation to use a conformant F34 implementation? Our rough estimation is that this will be ready around the end of this month or early next month.
Thanks,
Chris
Dmitry Torokhov
maintainerRe: [PATCH v2 05/06] input synaptics-rmi4: Add firmware update support
Quoted 72 lines · Christopher Heiny
Quoted 63 lines · Dmitry Torokhov
Quoted 55 lines · Christopher Heiny
[I sent this last Thursday, but it never showed up on the input list. I'm assuming nobody else saw it.]
Quoted 44 lines · Dmitry Torokhov
Quoted 35 lines · Christopher Heiny
Quoted 29 lines · Dmitry Torokhov
Quoted 22 lines · Christopher Heiny
Quoted 22 lines · Dmitry Torokhov
Quoted 11 lines
Quoted 11 lines
Hi Christopher,
Quoted 2 lines · Christopher Heiny
Quoted 2 lines
Add support for updating firmware on RMI4 devices with V5 bootloader.
I am wondering why F34 is not following the staindard RMI function implementation. By that I mean that it does not declare itself as struct
rmi_function_handlerand does not rely on RMI core to bind itself to the device if device supports it.Hi Dmitry,
We originally had an F34 implementation that followed the RMI4 function standard and exposed most of the basic F34 operations via sysfs. However, we got feedback (both on LKML and offline) (a) recommending to use
request_firmware, and (b) improve reflash times while (c) reducing impact on boot time, and (d) "get rid of all that sysfs crap" (paraphrased, but close to it).Quoted 5 lines
Quoted 5 lines
So after looking at how some other drivers use
request_firmware, we came up with the current approach. Switching torequest_firmwaredefinitely sped up the reflash times! Including a check to see if firmware update is required before setting up the RMI4 sensor/function structures also significantly reduced boot times.Quoted 4 lines
I am not suggesting you stop using request-firmware or introduce bazillion of new sysfs attributes. I just wondered why you have manual "binding" of F34 functionality instead of standrad RMI4 function binding, liek you do for F01, F11 and so forth.
Quoted 7 lines
Sorry! My answer wasn't very clear on that part, was it?
The manual binding gets the reflash (if required) done very early in the boot/probe process. This eliminates the need to set up the whole sensor + functions structure, tear it down in order to reflash, and then build it all back up again. It is felt that the time savings is significant, especially on highly featured products.
Quoted 6 lines
I am sorry but I have hard time accepting this argument. How often do you reflash devices during normal operation and how long does it take to initialize the device compared to getting entire userspace up and running to be able to actually supply or serve flash data (even without using usermode helper to flash you need filesystem with the firmware to be mounted)?
Quoted 6 lines
That was my argument exactly, but that was the direction we were pushed. I'd much rather implement it as we discussed offline earlier this week. If you were to say: "I'm sorry, but this simply can't be merged as it stands." you wouldn't get any argument from me on technical grounds. There might be people who will argue about the additional calendar time it would take to restructure it, though.
Quoted 7 lines
OK, then I will just say this: "I'm sorry, but this simply can't be merged as it stands."
Now, I am talking about mainline here, I am fairly certain we can resolve scheduling issues between what you currently have and what is needed in the
end.
Quoted 4 lines
OK. The question on our end becomes - can we accept the current implementation as a baseline while we rework the implementation to use a conformant F34 implementation? Our rough estimation is that this will be ready around the end of this month or early next month.
Chris,
We have a couple months till the next merge window.
Thanks.
Signature · 1 line
Dmitry
PATCH v2 6/6 input synaptics-rmi4: Use request_firmware_nowait
In reply to Christopher HeinyReplace request_firmware() and our own work_queue entry, and use request_firmware_nowait() instead.
---
drivers/input/rmi4/rmi_fw_update.c | 233 +++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 124 deletions(-)
drivers/input/rmi4/rmi_fw_update.c +109 -124
@@ -120,7 +120,6 @@ struct rmi_fw_update_data {struct rmi_f34_control_status f34_controls;const u8 *firmware_data;const u8 *config_data; -struct work_struct update_work; }; static void rmi_extract_header(const u8 *data, int pos,
@@ -260,11 +259,6 @@ static int rmi_wait_for_idle(struct rmi_fw_update_data *data, int timeout_ms) !data->f34_controls.program_enabled,"Bootloader is idle but program_enabled bit isn't set.\n" )) -/* -* This works around a bug in certain device -* firmwares, where the idle state is reached, -* but the program_enabled bit is not yet set. -*/ continue;return 0 ; }
@@ -482,7 +476,8 @@ static int rmi_write_blocks(struct rmi_fw_update_data *data, u8 *block_ptr,return retval; } - retval =rmi_write (data->rmi_dev, data->f34_status_address, cmd); + retval =rmi_write (data->rmi_dev, data->f34_status_address, + cmd);if (retval) {dev_err (&data->rmi_dev->dev,"Failed to write command for block %d. Code=%d.\n" , block_num, retval);
@@ -600,89 +595,30 @@ static bool rmi_go_nogo(struct rmi_fw_update_data *data,return false; } -static const char rmi_fw_name_format[] ="%s.img" ; - -static void rmi_fw_update (struct rmi_device *rmi_dev) +static void rmi_do_update (const struct firmware *fw_entry,void *context) { +struct rmi_device *rmi_dev = context; +struct rmi_driver_data *drv_data =dev_get_drvdata (&rmi_dev->dev); +struct rmi_fw_update_data *data = drv_data->fw_update_data; +struct rmi_image_header *header =NULL ;struct timespec start;struct timespec end;s64 duration_ns; -char *firmware_name; -const struct firmware *fw_entry =NULL ; -int retval; -struct rmi_image_header *header =NULL ; -u8 pdt_props; -struct rmi_driver_data *drv_data =dev_get_drvdata (&rmi_dev->dev); -struct rmi_fw_update_data *data = drv_data->fw_update_data; -const struct rmi_device_platform_data *pdata = -rmi_get_platform_data (rmi_dev); - -dev_dbg (&rmi_dev->dev,"%s called.\n" , __func__); -dev_dbg (&rmi_dev->dev,"force: %d\n" , data->force); -dev_dbg (&rmi_dev->dev,"img_name: %s\n" , data->img_name); -dev_dbg (&rmi_dev->dev,"firmware_name: %s\n" , pdata->firmware_name); -getnstimeofday (&start); - - firmware_name =kcalloc (RMI_NAME_BUFFER_SIZE ,sizeof (char ),GFP_KERNEL ); -if (!firmware_name) { -dev_err (&rmi_dev->dev,"Failed to allocate firmware_name.\n" ); - goto done; +if (!fw_entry) { +dev_err (&rmi_dev->dev,"Firmware was not available.\n" ); + goto error_exit; } + header =kzalloc (sizeof (struct rmi_image_header ),GFP_KERNEL );if (!header) { -dev_err (&rmi_dev->dev,"Failed to allocate header.\n" ); - goto done; +dev_err (&rmi_dev->dev,"Failed to allocate image header.\n" ); + goto error_exit; } - retval =rmi_read (rmi_dev,PDT_PROPERTIES_LOCATION , &pdt_props); -if (retval) { -dev_warn (&rmi_dev->dev, -"Failed to read PDT props at %#06x (code %d). Assuming 0x00.\n" , -PDT_PROPERTIES_LOCATION , retval); - } -if (pdt_props &RMI_PDT_PROPS_HAS_BSR ) { -dev_warn (&rmi_dev->dev, -"Firmware update for LTS not currently supported.\n" ); - goto done; - } - - retval =rmi_f01_read_properties (rmi_dev, data->f01_pdt.query_base_addr, - &data->f01_props); -if (retval) { -dev_err (&rmi_dev->dev,"F01 queries failed, code = %d.\n" , - retval); - goto done; - } - retval =rmi_read_f34_queries (data); -if (retval) { -dev_err (&rmi_dev->dev,"F34 queries failed, code = %d.\n" , - retval); - goto done; - } -if (data->img_name && data->img_name[0 ]) -snprintf (firmware_name,RMI_NAME_BUFFER_SIZE , - rmi_fw_name_format, data->img_name); -else if (pdata->firmware_name && pdata->firmware_name[0 ]) -snprintf (firmware_name,RMI_NAME_BUFFER_SIZE , - rmi_fw_name_format, pdata->firmware_name); -else { -if (!data->f01_props.product_id[0 ]) { -dev_err (&rmi_dev->dev,"Could not determine fw image name - will not update fw.\n" ); - goto done; - } -snprintf (firmware_name,RMI_NAME_BUFFER_SIZE , - rmi_fw_name_format, data->f01_props.product_id); - } -dev_info (&rmi_dev->dev,"Requesting %s.\n" , firmware_name); - retval =request_firmware (&fw_entry, firmware_name, &rmi_dev->dev); -if (retval !=0 ) { -dev_err (&rmi_dev->dev,"Firmware %s not available, code = %d\n" , - firmware_name, retval); - goto done; - } +getnstimeofday (&start); -dev_dbg (&rmi_dev->dev,"Got firmware %s, size: %d.\n" , firmware_name, +dev_dbg (&rmi_dev->dev,"Got firmware, size: %d.\n" , fw_entry->size);rmi_extract_header (fw_entry->data,0 , header); dev_dbg(&rmi_dev->dev, "Img checksum: %#08X\n",
@@ -722,36 +658,98 @@ static void rmi_fw_update(struct rmi_device *rmi_dev)dev_dbg (&rmi_dev->dev,"Go/NoGo said don't update.\n" ); } -if (fw_entry) -release_firmware (fw_entry); +release_firmware (fw_entry); - -done:getnstimeofday (&end); duration_ns =timespec_to_ns (&end) -timespec_to_ns (&start);dev_dbg (&rmi_dev->dev,"Time to update fw: %lld ns.\n" , duration_ns); -kfree (firmware_name);kfree (header); +error_exit: +clear_bit (0 , &data->busy);return ; } -static int rmi_device_update_firmware (struct rmi_device *rmi_dev) +static const char rmi_fw_name_format[] ="%s.img" ; + +static int rmi_request_fw (struct rmi_device *rmi_dev) { -struct device *dev = &rmi_dev->dev; -struct rmi_driver_data *drv_data =dev_get_drvdata (dev); +struct rmi_driver_data *drv_data =dev_get_drvdata (&rmi_dev->dev);struct rmi_fw_update_data *data = drv_data->fw_update_data; -int retval; +const struct rmi_device_platform_data *pdata = +rmi_get_platform_data (rmi_dev); +char *firmware_name; +int error; +u8 pdt_props; - retval =rmi_find_f01_and_f34 (data); -if (retval <0 ) -return retval; + error =rmi_find_f01_and_f34 (data); +if (error <0 ) +return error; -rmi_fw_update (rmi_dev); +dev_dbg (&rmi_dev->dev,"%s called.\n" , __func__); +dev_dbg (&rmi_dev->dev,"force: %d\n" , data->force); +dev_dbg (&rmi_dev->dev,"img_name: %s\n" , data->img_name); +dev_dbg (&rmi_dev->dev,"firmware_name: %s\n" , pdata->firmware_name); -clear_bit (0 , &data->busy); -return 0 ; + error =rmi_read (rmi_dev,PDT_PROPERTIES_LOCATION , &pdt_props); +if (error) { +dev_warn (&rmi_dev->dev, +"Failed to read PDT props at %#06x (code %d). Assuming 0x00.\n" , +PDT_PROPERTIES_LOCATION , error); + } +if (pdt_props &RMI_PDT_PROPS_HAS_BSR ) { +dev_warn (&rmi_dev->dev, +"Firmware update for LTS not currently supported.\n" ); +return -EINVAL ; + } + + error =rmi_f01_read_properties (rmi_dev, data->f01_pdt.query_base_addr, + &data->f01_props); +if (error) { +dev_err (&rmi_dev->dev,"F01 queries failed, code = %d.\n" , + error); +return error; + } + error =rmi_read_f34_queries (data); +if (error) { +dev_err (&rmi_dev->dev,"F34 queries failed, code = %d.\n" , + error); +return error; + } + + firmware_name =kcalloc (RMI_NAME_BUFFER_SIZE ,sizeof (char ),GFP_KERNEL ); +if (!firmware_name) { +dev_err (&rmi_dev->dev,"Failed to allocate firmware_name.\n" ); +return -ENOMEM ; + } + +if (data->img_name && data->img_name[0 ]) +snprintf (firmware_name,RMI_NAME_BUFFER_SIZE , + rmi_fw_name_format, data->img_name); +else if (pdata->firmware_name && pdata->firmware_name[0 ]) +snprintf (firmware_name,RMI_NAME_BUFFER_SIZE , + rmi_fw_name_format, pdata->firmware_name); +else { +if (!data->f01_props.product_id[0 ]) { +dev_err (&rmi_dev->dev,"Could not determine fw image name - will not update fw.\n" ); + error = -EINVAL ; + goto done; + } +snprintf (firmware_name,RMI_NAME_BUFFER_SIZE , + rmi_fw_name_format, data->f01_props.product_id); + } +dev_info (&rmi_dev->dev,"Requesting %s.\n" , firmware_name); + error =request_firmware_nowait (THIS_MODULE ,FW_ACTION_HOTPLUG , + firmware_name, &rmi_dev->dev, +GFP_KERNEL , rmi_dev, rmi_do_update); +if (error) +dev_err (&rmi_dev->dev,"Request firmware failed for %s, code = %d\n" , + firmware_name, error); + +done: +kfree (firmware_name); +return error; } static ssize_t rmi_fw_update_img_name_show(struct device *dev,
@@ -788,7 +786,8 @@ static ssize_t rmi_fw_update_img_name_store(struct device *dev, }static ssize_t rmi_fw_update_force_show (struct device *dev, -struct device_attribute *attr,char *buf) +struct device_attribute *attr, +char *buf) {struct rmi_device *rmi_dev =to_rmi_device (dev);struct rmi_driver_data *drv_data =dev_get_drvdata (&rmi_dev->dev);
@@ -853,34 +852,21 @@ static ssize_t rmi_fw_update_store(struct device *dev,if (test_and_set_bit (0 , &data->busy))return -EBUSY ; -if (val) -/* -* TODO: Here we start a work thread to go do the update, but -* maybe we can just use request_firmware_timeout(). -*/ -schedule_work (&data->update_work); -else +if (val) { + retval =rmi_request_fw (rmi_dev); +if (retval) { +dev_err (dev,"Firmware request failed, code: %d" , + retval); +clear_bit (0 , &data->busy); + } + }else {clear_bit (0 , &data->busy); + }return count; } -static void rmi_update_work (struct work_struct *work) -{ -struct rmi_fw_update_data *data = - container_of(work, struct rmi_fw_update_data, update_work); -struct rmi_device *rmi_dev = data->rmi_dev; -int error; - -dev_dbg (&rmi_dev->dev,"%s runs.\n" , __func__); - error =rmi_device_update_firmware (rmi_dev); -if (error <0 ) -dev_err (&rmi_dev->dev,"Firmware update attempt failed with code: %d." , - error); -clear_bit (0 , &data->busy); -} - -static DEVICE_ATTR(update_force, +static DEVICE_ATTR(fw_force_update, (S_IRUGO | S_IWUGO), rmi_fw_update_force_show, rmi_fw_update_force_store); static DEVICE_ATTR(fw_img_name,
@@ -892,7 +878,7 @@ static DEVICE_ATTR(fw_update, rmi_fw_update_show, rmi_fw_update_store);static struct attribute *rmi_fw_update_attrs[] = { - &dev_attr_update_force.attr, + &dev_attr_fw_force_update.attr, &dev_attr_fw_img_name.attr, &dev_attr_fw_update.attr,NULL
@@ -904,9 +890,8 @@ static const struct attribute_group rmi_fw_update_attributes = {/* * Allocate data needed by firmware update and initialize relevant -* structures (like sysfs, work, and so on). You'll need to call -* rmi_fw_update_cleanup() to free the storage and tear down the -* structures. +* structures (like sysfs). You'll need to call rmi_fw_update_cleanup() +* to free the storage and tear down the structures. */ void rmi_fw_update_init (struct rmi_device *rmi_dev) {
@@ -918,13 +903,13 @@ void rmi_fw_update_init(struct rmi_device *rmi_dev) data =kzalloc (sizeof (struct rmi_fw_update_data ),GFP_KERNEL ); - error =sysfs_create_group (&rmi_dev->dev.kobj, &rmi_fw_update_attributes); + error =sysfs_create_group (&rmi_dev->dev.kobj, + &rmi_fw_update_attributes);if (error) {dev_warn (&rmi_dev->dev,"Failed to create fw update sysfs attributes.\n" );return ; } -INIT_WORK (&data->update_work, rmi_update_work); data->rmi_dev = rmi_dev; drv_data->fw_update_data = data; }