Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29fd0ec2 authored by Nick Dyer's avatar Nick Dyer Committed by Dmitry Torokhov
Browse files

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: default avatarNick Dyer <nick@shmanahar.org>
Tested-by: default avatarChris Healy <cphealy@gmail.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 792f497b
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -74,6 +74,17 @@ config RMI4_F30
	  Function 30 provides GPIO and LED support for RMI4 devices. This
	  includes support for buttons on TouchPads and ClickPads.

config RMI4_F34
	bool "RMI4 Function 34 (Device reflash)"
	depends on RMI4_CORE
	select FW_LOADER
	help
	  Say Y here if you want to add support for RMI4 function 34.

	  Function 34 provides support for upgrading the firmware on the RMI4
	  device via the firmware loader interface. This is triggered using a
	  sysfs attribute.

config RMI4_F54
	bool "RMI4 Function 54 (Analog diagnostics)"
	depends on RMI4_CORE
+1 −0
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o
rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o

# Transports
+3 −0
Original line number Diff line number Diff line
@@ -315,6 +315,9 @@ static struct rmi_function_handler *fn_handlers[] = {
#ifdef CONFIG_RMI4_F30
	&rmi_f30_handler,
#endif
#ifdef CONFIG_RMI4_F34
	&rmi_f34_handler,
#endif
#ifdef CONFIG_RMI4_F54
	&rmi_f54_handler,
#endif
+74 −31
Original line number Diff line number Diff line
@@ -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,11 +260,17 @@ 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 rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
		 int (*callback)(struct rmi_device *rmi_dev,
					void *ctx,
					const struct pdt_entry *entry))
		 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;

+24 −0
Original line number Diff line number Diff line
@@ -95,12 +95,36 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
bool rmi_is_physical_driver(struct device_driver *);
int rmi_register_physical_driver(void);
void rmi_unregister_physical_driver(void);
void rmi_free_function_list(struct rmi_device *rmi_dev);
int rmi_enable_sensor(struct rmi_device *rmi_dev);
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_probe_interrupts(struct rmi_driver_data *data);
int rmi_init_functions(struct rmi_driver_data *data);
int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx,
		      const struct pdt_entry *pdt);

char *rmi_f01_get_product_ID(struct rmi_function *fn);

#ifdef CONFIG_RMI4_F34
int rmi_f34_create_sysfs(struct rmi_device *rmi_dev);
void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev);
#else
static inline int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
{
	return 0;
}

static inline void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev)
{
}
#endif /* CONFIG_RMI_F34 */

extern struct rmi_function_handler rmi_f01_handler;
extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler;
extern struct rmi_function_handler rmi_f30_handler;
extern struct rmi_function_handler rmi_f34_handler;
extern struct rmi_function_handler rmi_f54_handler;
#endif
Loading