summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/rmi4/rmi_driver.c83
-rw-r--r--drivers/input/rmi4/rmi_driver.h2
-rw-r--r--include/linux/rmi.h1
3 files changed, 67 insertions, 19 deletions
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index 2b17d8cb3d10..f04fc4152c1f 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -215,6 +215,7 @@ static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
static int rmi_irq_init(struct rmi_device *rmi_dev)
{
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
int irq_flags = irq_get_trigger_type(pdata->irq);
int ret;
@@ -232,6 +233,8 @@ static int rmi_irq_init(struct rmi_device *rmi_dev)
return ret;
}
+ data->enabled = true;
+
return 0;
}
@@ -866,17 +869,54 @@ err_put_fn:
return error;
}
-int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake)
{
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
int irq = pdata->irq;
- int retval = 0;
+ int irq_flags;
+ int retval;
- retval = rmi_suspend_functions(rmi_dev);
- if (retval)
- dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
- retval);
+ mutex_lock(&data->enabled_mutex);
+
+ if (data->enabled)
+ goto out;
+
+ enable_irq(irq);
+ data->enabled = true;
+ 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);
+ }
+
+ /*
+ * Call rmi_process_interrupt_requests() after enabling irq,
+ * otherwise we may lose interrupt on edge-triggered systems.
+ */
+ irq_flags = irq_get_trigger_type(pdata->irq);
+ if (irq_flags & IRQ_TYPE_EDGE_BOTH)
+ rmi_process_interrupt_requests(rmi_dev);
+
+out:
+ mutex_unlock(&data->enabled_mutex);
+}
+
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake)
+{
+ struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
+ struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
+ int irq = pdata->irq;
+ int retval;
+
+ mutex_lock(&data->enabled_mutex);
+
+ if (!data->enabled)
+ goto out;
+ data->enabled = false;
disable_irq(irq);
if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
retval = enable_irq_wake(irq);
@@ -885,24 +925,30 @@ int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
"Failed to enable irq for wake: %d\n",
retval);
}
+
+out:
+ mutex_unlock(&data->enabled_mutex);
+}
+
+int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake)
+{
+ int retval;
+
+ retval = rmi_suspend_functions(rmi_dev);
+ if (retval)
+ dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n",
+ retval);
+
+ rmi_disable_irq(rmi_dev, enable_wake);
return retval;
}
EXPORT_SYMBOL_GPL(rmi_driver_suspend);
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);
- }
+ rmi_enable_irq(rmi_dev, clear_wake);
retval = rmi_resume_functions(rmi_dev);
if (retval)
@@ -916,10 +962,8 @@ 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_disable_irq(rmi_dev, false);
rmi_f34_remove_sysfs(rmi_dev);
rmi_free_function_list(rmi_dev);
@@ -1108,6 +1152,7 @@ static int rmi_driver_probe(struct device *dev)
}
mutex_init(&data->irq_mutex);
+ mutex_init(&data->enabled_mutex);
retval = rmi_probe_interrupts(data);
if (retval)
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 5b201f369505..c9fe3d3deef3 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -101,6 +101,8 @@ 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);
+void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake);
+void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake);
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);
diff --git a/include/linux/rmi.h b/include/linux/rmi.h
index 0b118ab47b8d..621f098f1243 100644
--- a/include/linux/rmi.h
+++ b/include/linux/rmi.h
@@ -356,6 +356,7 @@ struct rmi_driver_data {
u8 num_tx_electrodes;
bool enabled;
+ struct mutex enabled_mutex;
};
int rmi_register_transport_device(struct rmi_transport_dev *xport);