Input: synaptics_i2c - switch to using __cancel_delayed_work()
cancel_delayed_work() may spin and therefore should not be used in interrupt contexts. Acked-by: Mike Rapoport <mike@compulab.co.il> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
This commit is contained in:
@@ -203,7 +203,7 @@ MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)");
|
|||||||
* and the irq configuration should be set to Falling Edge Trigger
|
* and the irq configuration should be set to Falling Edge Trigger
|
||||||
*/
|
*/
|
||||||
/* Control IRQ / Polling option */
|
/* Control IRQ / Polling option */
|
||||||
static int polling_req;
|
static bool polling_req;
|
||||||
module_param(polling_req, bool, 0444);
|
module_param(polling_req, bool, 0444);
|
||||||
MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)");
|
MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)");
|
||||||
|
|
||||||
@@ -217,6 +217,7 @@ struct synaptics_i2c {
|
|||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
struct delayed_work dwork;
|
struct delayed_work dwork;
|
||||||
|
spinlock_t lock;
|
||||||
int no_data_count;
|
int no_data_count;
|
||||||
int no_decel_param;
|
int no_decel_param;
|
||||||
int reduce_report_param;
|
int reduce_report_param;
|
||||||
@@ -366,17 +367,28 @@ static bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
|
|||||||
return xy_delta || gesture;
|
return xy_delta || gesture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void synaptics_i2c_reschedule_work(struct synaptics_i2c *touch,
|
||||||
|
unsigned long delay)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&touch->lock, flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If work is already scheduled then subsequent schedules will not
|
||||||
|
* change the scheduled time that's why we have to cancel it first.
|
||||||
|
*/
|
||||||
|
__cancel_delayed_work(&touch->dwork);
|
||||||
|
schedule_delayed_work(&touch->dwork, delay);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&touch->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
|
static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct synaptics_i2c *touch = dev_id;
|
struct synaptics_i2c *touch = dev_id;
|
||||||
|
|
||||||
/*
|
synaptics_i2c_reschedule_work(touch, 0);
|
||||||
* We want to have the work run immediately but it might have
|
|
||||||
* already been scheduled with a delay, that's why we have to
|
|
||||||
* cancel it first.
|
|
||||||
*/
|
|
||||||
cancel_delayed_work(&touch->dwork);
|
|
||||||
schedule_delayed_work(&touch->dwork, 0);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
@@ -452,7 +464,7 @@ static void synaptics_i2c_work_handler(struct work_struct *work)
|
|||||||
* We poll the device once in THREAD_IRQ_SLEEP_SECS and
|
* We poll the device once in THREAD_IRQ_SLEEP_SECS and
|
||||||
* if error is detected, we try to reset and reconfigure the touchpad.
|
* if error is detected, we try to reset and reconfigure the touchpad.
|
||||||
*/
|
*/
|
||||||
schedule_delayed_work(&touch->dwork, delay);
|
synaptics_i2c_reschedule_work(touch, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int synaptics_i2c_open(struct input_dev *input)
|
static int synaptics_i2c_open(struct input_dev *input)
|
||||||
@@ -465,7 +477,7 @@ static int synaptics_i2c_open(struct input_dev *input)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (polling_req)
|
if (polling_req)
|
||||||
schedule_delayed_work(&touch->dwork,
|
synaptics_i2c_reschedule_work(touch,
|
||||||
msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
|
msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -521,6 +533,7 @@ struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client)
|
|||||||
touch->scan_rate_param = scan_rate;
|
touch->scan_rate_param = scan_rate;
|
||||||
set_scan_rate(touch, scan_rate);
|
set_scan_rate(touch, scan_rate);
|
||||||
INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler);
|
INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler);
|
||||||
|
spin_lock_init(&touch->lock);
|
||||||
|
|
||||||
return touch;
|
return touch;
|
||||||
}
|
}
|
||||||
@@ -535,14 +548,12 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client,
|
|||||||
if (!touch)
|
if (!touch)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
i2c_set_clientdata(client, touch);
|
|
||||||
|
|
||||||
ret = synaptics_i2c_reset_config(client);
|
ret = synaptics_i2c_reset_config(client);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_mem_free;
|
goto err_mem_free;
|
||||||
|
|
||||||
if (client->irq < 1)
|
if (client->irq < 1)
|
||||||
polling_req = 1;
|
polling_req = true;
|
||||||
|
|
||||||
touch->input = input_allocate_device();
|
touch->input = input_allocate_device();
|
||||||
if (!touch->input) {
|
if (!touch->input) {
|
||||||
@@ -563,7 +574,7 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client,
|
|||||||
dev_warn(&touch->client->dev,
|
dev_warn(&touch->client->dev,
|
||||||
"IRQ request failed: %d, "
|
"IRQ request failed: %d, "
|
||||||
"falling back to polling\n", ret);
|
"falling back to polling\n", ret);
|
||||||
polling_req = 1;
|
polling_req = true;
|
||||||
synaptics_i2c_reg_set(touch->client,
|
synaptics_i2c_reg_set(touch->client,
|
||||||
INTERRUPT_EN_REG, 0);
|
INTERRUPT_EN_REG, 0);
|
||||||
}
|
}
|
||||||
@@ -580,12 +591,14 @@ static int __devinit synaptics_i2c_probe(struct i2c_client *client,
|
|||||||
"Input device register failed: %d\n", ret);
|
"Input device register failed: %d\n", ret);
|
||||||
goto err_input_free;
|
goto err_input_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, touch);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_input_free:
|
err_input_free:
|
||||||
input_free_device(touch->input);
|
input_free_device(touch->input);
|
||||||
err_mem_free:
|
err_mem_free:
|
||||||
i2c_set_clientdata(client, NULL);
|
|
||||||
kfree(touch);
|
kfree(touch);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -596,7 +609,7 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client)
|
|||||||
struct synaptics_i2c *touch = i2c_get_clientdata(client);
|
struct synaptics_i2c *touch = i2c_get_clientdata(client);
|
||||||
|
|
||||||
if (!polling_req)
|
if (!polling_req)
|
||||||
free_irq(touch->client->irq, touch);
|
free_irq(client->irq, touch);
|
||||||
|
|
||||||
input_unregister_device(touch->input);
|
input_unregister_device(touch->input);
|
||||||
i2c_set_clientdata(client, NULL);
|
i2c_set_clientdata(client, NULL);
|
||||||
@@ -627,7 +640,7 @@ static int synaptics_i2c_resume(struct i2c_client *client)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
schedule_delayed_work(&touch->dwork,
|
synaptics_i2c_reschedule_work(touch,
|
||||||
msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
|
msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user