diff options
| author | Nick Dyer <nick.dyer@itdev.co.uk> | 2015-04-30 16:08:03 +0100 |
|---|---|---|
| committer | Nick Dyer <nick.dyer@itdev.co.uk> | 2015-05-01 15:16:50 +0100 |
| commit | c497cf80cda116bc2c2f478b96f21a917e5ca464 (patch) | |
| tree | 824fb0052e9cf04da277d3c284f448358a8f350a | |
| parent | 17ef3ea96b4a79b7381745d62a887862c3a22a6d (diff) | |
| download | olio-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.c | 47 |
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); |