Skip to content

Commit

Permalink
Input: atmel_mxt_ts - delay enabling IRQ when not using regulators
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
ndyer committed Apr 26, 2016
1 parent 67a3eea commit 64c9dad
Showing 1 changed file with 31 additions and 16 deletions.
47 changes: 31 additions & 16 deletions drivers/input/touchscreen/atmel_mxt_ts.c
Original file line number Diff line number Diff line change
Expand Up @@ -1793,9 +1793,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;
Expand Down Expand Up @@ -2839,7 +2853,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);
Expand Down Expand Up @@ -3377,7 +3393,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)
Expand All @@ -3390,21 +3405,17 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
init_completion(&data->reset_completion);
init_completion(&data->crc_completion);

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_fw_attr_group);
if (error) {
Expand All @@ -3420,7 +3431,8 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
return 0;

err_free_irq:
free_irq(client->irq, data);
if (data->irq)
free_irq(data->irq, data);
err_free_mem:
kfree(data);
return error;
Expand All @@ -3432,7 +3444,10 @@ static int mxt_remove(struct i2c_client *client)

sysfs_remove_group(&client->dev.kobj, &mxt_fw_attr_group);
mxt_sysfs_remove(data);
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);
Expand Down

0 comments on commit 64c9dad

Please sign in to comment.