Input: synaptics-rmi4 - add support for F34 device reflash
Add support for updating firmware, triggered by a sysfs attribute. This patch has been tested on Synaptics S7300. Signed-off-by: Nick Dyer <nick@shmanahar.org> Tested-by: Chris Healy <cphealy@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:

committed by
Dmitry Torokhov

parent
792f497b22
commit
29fd0ec2bd
@@ -35,14 +35,24 @@
|
||||
#define RMI_DEVICE_RESET_CMD 0x01
|
||||
#define DEFAULT_RESET_DELAY_MS 100
|
||||
|
||||
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);
|
||||
|
||||
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n");
|
||||
|
||||
mutex_lock(&data->irq_mutex);
|
||||
|
||||
devm_kfree(&rmi_dev->dev, data->irq_memory);
|
||||
data->irq_memory = NULL;
|
||||
data->irq_status = NULL;
|
||||
data->fn_irq_bits = NULL;
|
||||
data->current_irq_mask = NULL;
|
||||
data->new_irq_mask = NULL;
|
||||
|
||||
data->f01_container = NULL;
|
||||
data->f34_container = NULL;
|
||||
|
||||
/* Doing it in the reverse order so F01 will be removed last */
|
||||
list_for_each_entry_safe_reverse(fn, tmp,
|
||||
@@ -50,7 +60,10 @@ static void rmi_free_function_list(struct rmi_device *rmi_dev)
|
||||
list_del(&fn->node);
|
||||
rmi_unregister_function(fn);
|
||||
}
|
||||
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_free_function_list);
|
||||
|
||||
static int reset_one_function(struct rmi_function *fn)
|
||||
{
|
||||
@@ -147,24 +160,25 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
|
||||
if (!data)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&data->irq_mutex);
|
||||
if (!data->irq_status || !data->f01_container) {
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!rmi_dev->xport->attn_data) {
|
||||
error = rmi_read_block(rmi_dev,
|
||||
data->f01_container->fd.data_base_addr + 1,
|
||||
data->irq_status, data->num_of_irq_regs);
|
||||
if (error < 0) {
|
||||
dev_err(dev, "Failed to read irqs, code=%d\n", error);
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&data->irq_mutex);
|
||||
bitmap_and(data->irq_status, data->irq_status, data->current_irq_mask,
|
||||
data->irq_count);
|
||||
/*
|
||||
* At this point, irq_status has all bits that are set in the
|
||||
* interrupt status register and are enabled.
|
||||
*/
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
|
||||
/*
|
||||
* It would be nice to be able to use irq_chip to handle these
|
||||
@@ -180,6 +194,8 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
|
||||
if (data->input)
|
||||
input_sync(data->input);
|
||||
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -244,12 +260,18 @@ static int rmi_suspend_functions(struct rmi_device *rmi_dev)
|
||||
struct rmi_function *entry;
|
||||
int retval;
|
||||
|
||||
mutex_lock(&data->irq_mutex);
|
||||
|
||||
list_for_each_entry(entry, &data->function_list, node) {
|
||||
retval = suspend_one_function(entry);
|
||||
if (retval < 0)
|
||||
if (retval < 0) {
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -278,16 +300,22 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev)
|
||||
struct rmi_function *entry;
|
||||
int retval;
|
||||
|
||||
mutex_lock(&data->irq_mutex);
|
||||
|
||||
list_for_each_entry(entry, &data->function_list, node) {
|
||||
retval = resume_one_function(entry);
|
||||
if (retval < 0)
|
||||
if (retval < 0) {
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_sensor(struct rmi_device *rmi_dev)
|
||||
int rmi_enable_sensor(struct rmi_device *rmi_dev)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
@@ -297,6 +325,7 @@ static int enable_sensor(struct rmi_device *rmi_dev)
|
||||
|
||||
return rmi_process_interrupt_requests(rmi_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_enable_sensor);
|
||||
|
||||
/**
|
||||
* rmi_driver_set_input_params - set input device id and other data.
|
||||
@@ -502,10 +531,9 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev,
|
||||
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 empty_pages = 0;
|
||||
@@ -520,6 +548,7 @@ static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
|
||||
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_scan_pdt);
|
||||
|
||||
int rmi_read_register_desc(struct rmi_device *d, u16 addr,
|
||||
struct rmi_register_descriptor *rdesc)
|
||||
@@ -740,19 +769,15 @@ static int rmi_count_irqs(struct rmi_device *rmi_dev,
|
||||
int *irq_count = ctx;
|
||||
|
||||
*irq_count += pdt->interrupt_source_count;
|
||||
if (pdt->function_number == 0x01) {
|
||||
if (pdt->function_number == 0x01)
|
||||
data->f01_bootloader_mode =
|
||||
rmi_check_bootloader_mode(rmi_dev, pdt);
|
||||
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_initial_reset(struct rmi_device *rmi_dev,
|
||||
void *ctx, const struct pdt_entry *pdt)
|
||||
int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
|
||||
const struct pdt_entry *pdt)
|
||||
{
|
||||
int error;
|
||||
|
||||
@@ -787,6 +812,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev,
|
||||
/* F01 should always be on page 0. If we don't find it there, fail. */
|
||||
return pdt->page_start == 0 ? RMI_SCAN_CONTINUE : -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_initial_reset);
|
||||
|
||||
static int rmi_create_function(struct rmi_device *rmi_dev,
|
||||
void *ctx, const struct pdt_entry *pdt)
|
||||
@@ -828,6 +854,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
|
||||
|
||||
if (pdt->function_number == 0x01)
|
||||
data->f01_container = fn;
|
||||
else if (pdt->function_number == 0x34)
|
||||
data->f34_container = fn;
|
||||
|
||||
list_add_tail(&fn->node, &data->function_list);
|
||||
|
||||
@@ -893,6 +921,7 @@ static int rmi_driver_remove(struct device *dev)
|
||||
|
||||
disable_irq(irq);
|
||||
|
||||
rmi_f34_remove_sysfs(rmi_dev);
|
||||
rmi_free_function_list(rmi_dev);
|
||||
|
||||
return 0;
|
||||
@@ -919,13 +948,12 @@ static inline int rmi_driver_of_probe(struct device *dev,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int rmi_probe_interrupts(struct rmi_driver_data *data)
|
||||
int rmi_probe_interrupts(struct rmi_driver_data *data)
|
||||
{
|
||||
struct rmi_device *rmi_dev = data->rmi_dev;
|
||||
struct device *dev = &rmi_dev->dev;
|
||||
int irq_count;
|
||||
size_t size;
|
||||
void *irq_memory;
|
||||
int retval;
|
||||
|
||||
/*
|
||||
@@ -941,31 +969,38 @@ static int rmi_probe_interrupts(struct rmi_driver_data *data)
|
||||
dev_err(dev, "IRQ counting failed with code %d.\n", retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (data->f01_bootloader_mode)
|
||||
dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n");
|
||||
|
||||
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 = devm_kzalloc(dev, size * 4, GFP_KERNEL);
|
||||
if (!irq_memory) {
|
||||
data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL);
|
||||
if (!data->irq_memory) {
|
||||
dev_err(dev, "Failed to allocate memory for irq masks.\n");
|
||||
return retval;
|
||||
}
|
||||
|
||||
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;
|
||||
data->irq_status = data->irq_memory + size * 0;
|
||||
data->fn_irq_bits = data->irq_memory + size * 1;
|
||||
data->current_irq_mask = data->irq_memory + size * 2;
|
||||
data->new_irq_mask = data->irq_memory + size * 3;
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_probe_interrupts);
|
||||
|
||||
static int rmi_init_functions(struct rmi_driver_data *data)
|
||||
int rmi_init_functions(struct rmi_driver_data *data)
|
||||
{
|
||||
struct rmi_device *rmi_dev = data->rmi_dev;
|
||||
struct device *dev = &rmi_dev->dev;
|
||||
int irq_count;
|
||||
int retval;
|
||||
|
||||
mutex_lock(&data->irq_mutex);
|
||||
|
||||
irq_count = 0;
|
||||
rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__);
|
||||
retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function);
|
||||
@@ -990,12 +1025,16 @@ static int rmi_init_functions(struct rmi_driver_data *data)
|
||||
goto err_destroy_functions;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy_functions:
|
||||
rmi_free_function_list(rmi_dev);
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_init_functions);
|
||||
|
||||
static int rmi_driver_probe(struct device *dev)
|
||||
{
|
||||
@@ -1100,6 +1139,10 @@ static int rmi_driver_probe(struct device *dev)
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
retval = rmi_f34_create_sysfs(rmi_dev);
|
||||
if (retval)
|
||||
goto err;
|
||||
|
||||
if (data->input) {
|
||||
rmi_driver_set_input_name(rmi_dev, data->input);
|
||||
if (!rmi_dev->xport->input) {
|
||||
@@ -1117,7 +1160,7 @@ static int rmi_driver_probe(struct device *dev)
|
||||
|
||||
if (data->f01_container->dev.driver)
|
||||
/* Driver already bound, so enable ATTN now. */
|
||||
return enable_sensor(rmi_dev);
|
||||
return rmi_enable_sensor(rmi_dev);
|
||||
|
||||
return 0;
|
||||
|
||||
|
Reference in New Issue
Block a user