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

Commit 24d28e4f authored by Nick Dyer's avatar Nick Dyer Committed by Dmitry Torokhov
Browse files

Input: synaptics-rmi4 - convert irq distribution to irq_domain



Convert the RMI driver to use the standard mechanism for
distributing IRQs to the various functions.

Tested on:
* S7300 (F11, F34, F54)
* S7817 (F12, F34, F54)

Signed-off-by: default avatarNick Dyer <nick@shmanahar.org>
Acked-by: default avatarChristopher Heiny <cheiny@synaptics.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 8f6a652a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
#
config RMI4_CORE
	tristate "Synaptics RMI4 bus support"
	select IRQ_DOMAIN
	help
	  Say Y here if you want to support the Synaptics RMI4 bus.  This is
	  required for all RMI4 device support.
+49 −1
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@

#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/list.h>
#include <linux/pm.h>
#include <linux/rmi.h>
@@ -167,6 +169,39 @@ static inline void rmi_function_of_probe(struct rmi_function *fn)
{}
#endif

static struct irq_chip rmi_irq_chip = {
	.name = "rmi4",
};

static int rmi_create_function_irq(struct rmi_function *fn,
				   struct rmi_function_handler *handler)
{
	struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
	int i, error;

	for (i = 0; i < fn->num_of_irqs; i++) {
		set_bit(fn->irq_pos + i, fn->irq_mask);

		fn->irq[i] = irq_create_mapping(drvdata->irqdomain,
						fn->irq_pos + i);

		irq_set_chip_data(fn->irq[i], fn);
		irq_set_chip_and_handler(fn->irq[i], &rmi_irq_chip,
					 handle_simple_irq);
		irq_set_nested_thread(fn->irq[i], 1);

		error = devm_request_threaded_irq(&fn->dev, fn->irq[i], NULL,
					handler->attention, IRQF_ONESHOT,
					dev_name(&fn->dev), fn);
		if (error) {
			dev_err(&fn->dev, "Error %d registering IRQ\n", error);
			return error;
		}
	}

	return 0;
}

static int rmi_function_probe(struct device *dev)
{
	struct rmi_function *fn = to_rmi_function(dev);
@@ -178,6 +213,13 @@ static int rmi_function_probe(struct device *dev)

	if (handler->probe) {
		error = handler->probe(fn);
		if (error)
			return error;
	}

	if (fn->num_of_irqs && handler->attention) {
		error = rmi_create_function_irq(fn, handler);
		if (error)
			return error;
	}

@@ -230,12 +272,18 @@ int rmi_register_function(struct rmi_function *fn)

void rmi_unregister_function(struct rmi_function *fn)
{
	int i;

	rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n",
			fn->fd.function_number);

	device_del(&fn->dev);
	of_node_put(fn->dev.of_node);
	put_device(&fn->dev);

	for (i = 0; i < fn->num_of_irqs; i++)
		irq_dispose_mapping(fn->irq[i]);

}

/**
+9 −1
Original line number Diff line number Diff line
@@ -14,6 +14,12 @@

struct rmi_device;

/*
 * The interrupt source count in the function descriptor can represent up to
 * 6 interrupt sources in the normal manner.
 */
#define RMI_FN_MAX_IRQS	6

/**
 * struct rmi_function - represents the implementation of an RMI4
 * function for a particular device (basically, a driver for that RMI4 function)
@@ -26,6 +32,7 @@ struct rmi_device;
 * @irq_pos: The position in the irq bitfield this function holds
 * @irq_mask: For convenience, can be used to mask IRQ bits off during ATTN
 * interrupt handling.
 * @irqs: assigned virq numbers (up to num_of_irqs)
 *
 * @node: entry in device's list of functions
 */
@@ -36,6 +43,7 @@ struct rmi_function {
	struct list_head node;

	unsigned int num_of_irqs;
	int irq[RMI_FN_MAX_IRQS];
	unsigned int irq_pos;
	unsigned long irq_mask[];
};
@@ -76,7 +84,7 @@ struct rmi_function_handler {
	void (*remove)(struct rmi_function *fn);
	int (*config)(struct rmi_function *fn);
	int (*reset)(struct rmi_function *fn);
	int (*attention)(struct rmi_function *fn, unsigned long *irq_bits);
	irqreturn_t (*attention)(int irq, void *ctx);
	int (*suspend)(struct rmi_function *fn);
	int (*resume)(struct rmi_function *fn);
};
+20 −32
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/irqdomain.h>
#include <uapi/linux/input.h>
#include <linux/rmi.h>
#include "rmi_bus.h"
@@ -127,28 +128,11 @@ static int rmi_driver_process_config_requests(struct rmi_device *rmi_dev)
	return 0;
}

static void process_one_interrupt(struct rmi_driver_data *data,
				  struct rmi_function *fn)
{
	struct rmi_function_handler *fh;

	if (!fn || !fn->dev.driver)
		return;

	fh = to_rmi_function_handler(fn->dev.driver);
	if (fh->attention) {
		bitmap_and(data->fn_irq_bits, data->irq_status, fn->irq_mask,
				data->irq_count);
		if (!bitmap_empty(data->fn_irq_bits, data->irq_count))
			fh->attention(fn, data->fn_irq_bits);
	}
}

static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
{
	struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
	struct device *dev = &rmi_dev->dev;
	struct rmi_function *entry;
	int i;
	int error;

	if (!data)
@@ -173,16 +157,8 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
	 */
	mutex_unlock(&data->irq_mutex);

	/*
	 * It would be nice to be able to use irq_chip to handle these
	 * nested IRQs.  Unfortunately, most of the current customers for
	 * this driver are using older kernels (3.0.x) that don't support
	 * the features required for that.  Once they've shifted to more
	 * recent kernels (say, 3.3 and higher), this should be switched to
	 * use irq_chip.
	 */
	list_for_each_entry(entry, &data->function_list, node)
		process_one_interrupt(data, entry);
	for_each_set_bit(i, data->irq_status, data->irq_count)
		handle_nested_irq(irq_find_mapping(data->irqdomain, i));

	if (data->input)
		input_sync(data->input);
@@ -1000,9 +976,13 @@ EXPORT_SYMBOL_GPL(rmi_driver_resume);
static int rmi_driver_remove(struct device *dev)
{
	struct rmi_device *rmi_dev = to_rmi_device(dev);
	struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);

	rmi_disable_irq(rmi_dev, false);

	irq_domain_remove(data->irqdomain);
	data->irqdomain = NULL;

	rmi_f34_remove_sysfs(rmi_dev);
	rmi_free_function_list(rmi_dev);

@@ -1034,7 +1014,8 @@ 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;
	struct fwnode_handle *fwnode = rmi_dev->xport->dev->fwnode;
	int irq_count = 0;
	size_t size;
	int retval;

@@ -1045,7 +1026,6 @@ int rmi_probe_interrupts(struct rmi_driver_data *data)
	 * being accessed.
	 */
	rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__);
	irq_count = 0;
	data->bootloader_mode = false;

	retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs);
@@ -1057,6 +1037,15 @@ int rmi_probe_interrupts(struct rmi_driver_data *data)
	if (data->bootloader_mode)
		dev_warn(dev, "Device in bootloader mode.\n");

	/* Allocate and register a linear revmap irq_domain */
	data->irqdomain = irq_domain_create_linear(fwnode, irq_count,
						   &irq_domain_simple_ops,
						   data);
	if (!data->irqdomain) {
		dev_err(&rmi_dev->dev, "Failed to create IRQ domain\n");
		return PTR_ERR(data->irqdomain);
	}

	data->irq_count = irq_count;
	data->num_of_irq_regs = (data->irq_count + 7) / 8;

@@ -1079,10 +1068,9 @@ 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 irq_count = 0;
	int retval;

	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);
	if (retval < 0) {
+5 −5
Original line number Diff line number Diff line
@@ -681,9 +681,9 @@ static int rmi_f01_resume(struct rmi_function *fn)
	return 0;
}

static int rmi_f01_attention(struct rmi_function *fn,
			     unsigned long *irq_bits)
static irqreturn_t rmi_f01_attention(int irq, void *ctx)
{
	struct rmi_function *fn = ctx;
	struct rmi_device *rmi_dev = fn->rmi_dev;
	int error;
	u8 device_status;
@@ -692,7 +692,7 @@ static int rmi_f01_attention(struct rmi_function *fn,
	if (error) {
		dev_err(&fn->dev,
			"Failed to read device status: %d.\n", error);
		return error;
		return IRQ_RETVAL(error);
	}

	if (RMI_F01_STATUS_BOOTLOADER(device_status))
@@ -704,11 +704,11 @@ static int rmi_f01_attention(struct rmi_function *fn,
		error = rmi_dev->driver->reset_handler(rmi_dev);
		if (error) {
			dev_err(&fn->dev, "Device reset failed: %d\n", error);
			return error;
			return IRQ_RETVAL(error);
		}
	}

	return 0;
	return IRQ_HANDLED;
}

struct rmi_function_handler rmi_f01_handler = {
Loading