summaryrefslogtreecommitdiff
path: root/drivers/input/rmi4/rmi_driver.c
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2016-11-08 16:34:57 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2016-11-08 17:12:05 -0800
commit3aeed5b573f97b4525841cc07c1e948227af389f (patch)
treea3b5234fe5bed4e18c1370b88e10075dc1a98b3e /drivers/input/rmi4/rmi_driver.c
parent8029a283c4ac100dc4492993633d4c87a7da55d6 (diff)
Input: synaptics-rmi4 - move IRQ handling to rmi_driver
The attn IRQ is related to the chip, rather than the transport, so move all handling of interrupts to the core driver. This also makes sure that there are no races between interrupts and availability of the resources used by the core driver. Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/rmi4/rmi_driver.c')
-rw-r--r--drivers/input/rmi4/rmi_driver.c73
1 files changed, 69 insertions, 4 deletions
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 06feede3ce17..4f8d19794b01 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -17,6 +17,7 @@
#include <linux/bitmap.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/irq.h>
#include <linux/kconfig.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -136,7 +137,7 @@ static void process_one_interrupt(struct rmi_driver_data *data,
}
}
-int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
+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;
@@ -181,7 +182,42 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev)
return 0;
}
-EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests);
+
+static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
+{
+ struct rmi_device *rmi_dev = dev_id;
+ int ret;
+
+ ret = rmi_process_interrupt_requests(rmi_dev);
+ if (ret)
+ rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
+ "Failed to process interrupt request: %d\n", ret);
+
+ return IRQ_HANDLED;
+}
+
+static int rmi_irq_init(struct rmi_device *rmi_dev)
+{
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ int irq_flags = irq_get_trigger_type(pdata->irq);
+ int ret;
+
+ if (!irq_flags)
+ irq_flags = IRQF_TRIGGER_LOW;
+
+ ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL,
+ rmi_irq_fn, irq_flags | IRQF_ONESHOT,
+ dev_name(rmi_dev->xport->dev),
+ rmi_dev);
+ if (ret < 0) {
+ dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n",
+ pdata->irq);
+
+ return ret;
+ }
+
+ return 0;
+}
static int suspend_one_function(struct rmi_function *fn)
{
@@ -802,8 +838,10 @@ err_put_fn:
return error;
}
-int rmi_driver_suspend(struct rmi_device *rmi_dev)
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
{
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ int irq = pdata->irq;
int retval = 0;
retval = rmi_suspend_functions(rmi_dev);
@@ -811,14 +849,33 @@ int rmi_driver_suspend(struct rmi_device *rmi_dev)
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
retval);
+ disable_irq(irq);
+ if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+ retval = enable_irq_wake(irq);
+ if (!retval)
+ dev_warn(&rmi_dev->dev,
+ "Failed to enable irq for wake: %d\n",
+ retval);
+ }
return retval;
}
EXPORT_SYMBOL_GPL(rmi_driver_suspend);
-int rmi_driver_resume(struct rmi_device *rmi_dev)
+int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake)
{
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ int irq = pdata->irq;
int retval;
+ enable_irq(irq);
+ if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
+ retval = disable_irq_wake(irq);
+ if (!retval)
+ dev_warn(&rmi_dev->dev,
+ "Failed to disable irq for wake: %d\n",
+ retval);
+ }
+
retval = rmi_resume_functions(rmi_dev);
if (retval)
dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
@@ -831,6 +888,10 @@ 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_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ int irq = pdata->irq;
+
+ disable_irq(irq);
rmi_free_function_list(rmi_dev);
@@ -1050,6 +1111,10 @@ static int rmi_driver_probe(struct device *dev)
}
}
+ retval = rmi_irq_init(rmi_dev);
+ if (retval < 0)
+ goto err_destroy_functions;
+
if (data->f01_container->dev.driver)
/* Driver already bound, so enable ATTN now. */
return enable_sensor(rmi_dev);