summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Dyer <nick.dyer@itdev.co.uk>2015-04-30 16:08:03 +0100
committerNick Dyer <nick.dyer@itdev.co.uk>2015-05-01 15:16:50 +0100
commitc497cf80cda116bc2c2f478b96f21a917e5ca464 (patch)
tree824fb0052e9cf04da277d3c284f448358a8f350a
parent17ef3ea96b4a79b7381745d62a887862c3a22a6d (diff)
downloadolio-linux-3.10-c497cf80cda116bc2c2f478b96f21a917e5ca464.tar.xz
olio-linux-3.10-c497cf80cda116bc2c2f478b96f21a917e5ca464.zip
Input: atmel_mxt_ts - delay enabling IRQ when not using regulators
The path of enabling the IRQ in the probe function is not safe in level triggered operation, if it was already powered up and there is a message waiting on the device (eg finger down) because the object table has not yet been read. This forces the ISR into a hard loop. Delay enabling the interrupt until it is first needed. Signed-off-by: Nick Dyer <nick.dyer@itdev.co.uk>
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c47
1 files changed, 31 insertions, 16 deletions
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index d63c7bb56de..7298926a75c 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -1943,9 +1943,23 @@ static int mxt_acquire_irq(struct mxt_data *data)
{
int error;
- enable_irq(data->irq);
+ if (!data->irq) {
+ error = request_threaded_irq(data->client->irq, NULL,
+ mxt_interrupt,
+ data->pdata->irqflags | IRQF_ONESHOT,
+ data->client->name, data);
+ if (error) {
+ dev_err(&data->client->dev, "Error requesting irq\n");
+ return error;
+ }
+
+ /* Presence of data->irq means IRQ initialised */
+ data->irq = data->client->irq;
+ } else {
+ enable_irq(data->irq);
+ }
- if (data->use_retrigen_workaround) {
+ if (data->object_table && data->use_retrigen_workaround) {
error = mxt_process_messages_until_invalid(data);
if (error)
return error;
@@ -3022,7 +3036,9 @@ static int mxt_load_fw(struct device *dev)
goto release_firmware;
}
- enable_irq(data->irq);
+ ret = mxt_acquire_irq(data);
+ if (ret)
+ goto release_firmware;
/* Poll after 0.1s if no interrupt received */
schedule_delayed_work(&data->flash->work, HZ / 10);
@@ -3485,7 +3501,6 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
data->client = client;
data->pdata = pdata;
- data->irq = client->irq;
i2c_set_clientdata(client, data);
if (data->pdata->cfg_name)
@@ -3499,21 +3514,17 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
init_completion(&data->chg_completion);
mutex_init(&data->debug_msg_lock);
- error = request_threaded_irq(client->irq, NULL, mxt_interrupt,
- pdata->irqflags | IRQF_ONESHOT,
- client->name, data);
- if (error) {
- dev_err(&client->dev, "Failed to register interrupt\n");
- goto err_free_mem;
- }
-
if (pdata->suspend_mode == MXT_SUSPEND_REGULATOR) {
+ error = mxt_acquire_irq(data);
+ if (error)
+ goto err_free_mem;
+
error = mxt_probe_regulators(data);
if (error)
goto err_free_irq;
- }
- disable_irq(data->irq);
+ disable_irq(data->irq);
+ }
error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
if (error) {
@@ -3548,7 +3559,8 @@ err_remove_mem_access:
err_remove_sysfs_group:
sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
err_free_irq:
- free_irq(client->irq, data);
+ if (data->irq)
+ free_irq(data->irq, data);
err_free_mem:
kfree(data);
return error;
@@ -3563,7 +3575,10 @@ static int mxt_remove(struct i2c_client *client)
&data->mem_access_attr);
sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
- free_irq(data->irq, data);
+
+ if (data->irq)
+ free_irq(data->irq, data);
+
regulator_put(data->reg_avdd);
regulator_put(data->reg_vdd);
mxt_free_input_device(data);