aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-07-25 02:14:16 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-07-26 14:20:57 -0400
commit141586bc57f6083f36c18d86e1cfa5916a1e7c05 (patch)
tree2458a98edd2cbddcd981cb21723127feb5428d00 /drivers
parent75fba3b05d6ed82b975c1f8df8f8e08d5d81dee5 (diff)
Input: tsc2007 - properly shut off interrupts/delayed work
Properly shut off interrupts/delayed work by free-ing IRQ first and then ensuring that enable/disable is balanced. Also add __devinit/__devexit markings, restore poll delay/period scheduling logic, make sure we call exit_platform_hw() method when probe fails. Tested-by: Richard Röjfors <richard.rojfors.ext@mocean-labs.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/touchscreen/tsc2007.c72
1 files changed, 42 insertions, 30 deletions
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index b512697b227d..75fbd753a4d2 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -27,7 +27,8 @@
27#include <linux/i2c.h> 27#include <linux/i2c.h>
28#include <linux/i2c/tsc2007.h> 28#include <linux/i2c/tsc2007.h>
29 29
30#define TS_POLL_PERIOD msecs_to_jiffies(1) /* ms delay between samples */ 30#define TS_POLL_DELAY 1 /* ms delay between samples */
31#define TS_POLL_PERIOD 1 /* ms delay between samples */
31 32
32#define TSC2007_MEASURE_TEMP0 (0x0 << 4) 33#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
33#define TSC2007_MEASURE_AUX (0x2 << 4) 34#define TSC2007_MEASURE_AUX (0x2 << 4)
@@ -76,7 +77,7 @@ struct tsc2007 {
76 u16 model; 77 u16 model;
77 u16 x_plate_ohms; 78 u16 x_plate_ohms;
78 79
79 unsigned pendown; 80 bool pendown;
80 int irq; 81 int irq;
81 82
82 int (*get_pendown_state)(void); 83 int (*get_pendown_state)(void);
@@ -131,18 +132,18 @@ static void tsc2007_send_event(void *tsc)
131 } else 132 } else
132 rt = 0; 133 rt = 0;
133 134
134 /* Sample found inconsistent by debouncing or pressure is beyond 135 /*
136 * Sample found inconsistent by debouncing or pressure is beyond
135 * the maximum. Don't report it to user space, repeat at least 137 * the maximum. Don't report it to user space, repeat at least
136 * once more the measurement 138 * once more the measurement
137 */ 139 */
138 if (rt > MAX_12BIT) { 140 if (rt > MAX_12BIT) {
139 dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); 141 dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
140
141 schedule_delayed_work(&ts->work, TS_POLL_PERIOD);
142 return; 142 return;
143 } 143 }
144 144
145 /* NOTE: We can't rely on the pressure to determine the pen down 145 /*
146 * NOTE: We can't rely on the pressure to determine the pen down
146 * state, even this controller has a pressure sensor. The pressure 147 * state, even this controller has a pressure sensor. The pressure
147 * value can fluctuate for quite a while after lifting the pen and 148 * value can fluctuate for quite a while after lifting the pen and
148 * in some cases may not even settle at the expected value. 149 * in some cases may not even settle at the expected value.
@@ -157,7 +158,7 @@ static void tsc2007_send_event(void *tsc)
157 dev_dbg(&ts->client->dev, "DOWN\n"); 158 dev_dbg(&ts->client->dev, "DOWN\n");
158 159
159 input_report_key(input, BTN_TOUCH, 1); 160 input_report_key(input, BTN_TOUCH, 1);
160 ts->pendown = 1; 161 ts->pendown = true;
161 } 162 }
162 163
163 input_report_abs(input, ABS_X, x); 164 input_report_abs(input, ABS_X, x);
@@ -169,8 +170,6 @@ static void tsc2007_send_event(void *tsc)
169 dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", 170 dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
170 x, y, rt); 171 x, y, rt);
171 } 172 }
172
173 schedule_delayed_work(&ts->work, TS_POLL_PERIOD);
174} 173}
175 174
176static int tsc2007_read_values(struct tsc2007 *tsc) 175static int tsc2007_read_values(struct tsc2007 *tsc)
@@ -195,6 +194,7 @@ static void tsc2007_work(struct work_struct *work)
195{ 194{
196 struct tsc2007 *ts = 195 struct tsc2007 *ts =
197 container_of(to_delayed_work(work), struct tsc2007, work); 196 container_of(to_delayed_work(work), struct tsc2007, work);
197
198 if (unlikely(!ts->get_pendown_state() && ts->pendown)) { 198 if (unlikely(!ts->get_pendown_state() && ts->pendown)) {
199 struct input_dev *input = ts->input; 199 struct input_dev *input = ts->input;
200 200
@@ -204,7 +204,7 @@ static void tsc2007_work(struct work_struct *work)
204 input_report_abs(input, ABS_PRESSURE, 0); 204 input_report_abs(input, ABS_PRESSURE, 0);
205 input_sync(input); 205 input_sync(input);
206 206
207 ts->pendown = 0; 207 ts->pendown = false;
208 enable_irq(ts->irq); 208 enable_irq(ts->irq);
209 } else { 209 } else {
210 /* pen is still down, continue with the measurement */ 210 /* pen is still down, continue with the measurement */
@@ -212,6 +212,9 @@ static void tsc2007_work(struct work_struct *work)
212 212
213 tsc2007_read_values(ts); 213 tsc2007_read_values(ts);
214 tsc2007_send_event(ts); 214 tsc2007_send_event(ts);
215
216 schedule_delayed_work(&ts->work,
217 msecs_to_jiffies(TS_POLL_PERIOD));
215 } 218 }
216} 219}
217 220
@@ -221,7 +224,8 @@ static irqreturn_t tsc2007_irq(int irq, void *handle)
221 224
222 if (likely(ts->get_pendown_state())) { 225 if (likely(ts->get_pendown_state())) {
223 disable_irq_nosync(ts->irq); 226 disable_irq_nosync(ts->irq);
224 schedule_delayed_work(&ts->work, 0); 227 schedule_delayed_work(&ts->work,
228 msecs_to_jiffies(TS_POLL_DELAY));
225 } 229 }
226 230
227 if (ts->clear_penirq) 231 if (ts->clear_penirq)
@@ -230,8 +234,21 @@ static irqreturn_t tsc2007_irq(int irq, void *handle)
230 return IRQ_HANDLED; 234 return IRQ_HANDLED;
231} 235}
232 236
233static int tsc2007_probe(struct i2c_client *client, 237static void tsc2007_free_irq(struct tsc2007 *ts)
234 const struct i2c_device_id *id) 238{
239 free_irq(ts->irq, ts);
240 if (cancel_delayed_work_sync(&ts->work)) {
241 /*
242 * Work was pending, therefore we need to enable
243 * IRQ here to balance the disable_irq() done in the
244 * interrupt handler.
245 */
246 enable_irq(ts->irq);
247 }
248}
249
250static int __devinit tsc2007_probe(struct i2c_client *client,
251 const struct i2c_device_id *id)
235{ 252{
236 struct tsc2007 *ts; 253 struct tsc2007 *ts;
237 struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data; 254 struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
@@ -255,17 +272,15 @@ static int tsc2007_probe(struct i2c_client *client,
255 } 272 }
256 273
257 ts->client = client; 274 ts->client = client;
258 i2c_set_clientdata(client, ts); 275 ts->irq = client->irq;
259
260 ts->input = input_dev; 276 ts->input = input_dev;
277 INIT_DELAYED_WORK(&ts->work, tsc2007_work);
261 278
262 ts->model = pdata->model; 279 ts->model = pdata->model;
263 ts->x_plate_ohms = pdata->x_plate_ohms; 280 ts->x_plate_ohms = pdata->x_plate_ohms;
264 ts->get_pendown_state = pdata->get_pendown_state; 281 ts->get_pendown_state = pdata->get_pendown_state;
265 ts->clear_penirq = pdata->clear_penirq; 282 ts->clear_penirq = pdata->clear_penirq;
266 283
267 pdata->init_platform_hw();
268
269 snprintf(ts->phys, sizeof(ts->phys), 284 snprintf(ts->phys, sizeof(ts->phys),
270 "%s/input0", dev_name(&client->dev)); 285 "%s/input0", dev_name(&client->dev));
271 286
@@ -280,11 +295,7 @@ static int tsc2007_probe(struct i2c_client *client,
280 input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); 295 input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
281 input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); 296 input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
282 297
283 tsc2007_read_values(ts); 298 pdata->init_platform_hw();
284
285 ts->irq = client->irq;
286
287 INIT_DELAYED_WORK(&ts->work, tsc2007_work);
288 299
289 err = request_irq(ts->irq, tsc2007_irq, 0, 300 err = request_irq(ts->irq, tsc2007_irq, 0,
290 client->dev.driver->name, ts); 301 client->dev.driver->name, ts);
@@ -297,29 +308,30 @@ static int tsc2007_probe(struct i2c_client *client,
297 if (err) 308 if (err)
298 goto err_free_irq; 309 goto err_free_irq;
299 310
300 dev_info(&client->dev, "registered with irq (%d)\n", ts->irq); 311 i2c_set_clientdata(client, ts);
312
313 tsc2007_read_values(ts);
301 314
302 return 0; 315 return 0;
303 316
304 err_free_irq: 317 err_free_irq:
305 free_irq(ts->irq, ts); 318 tsc2007_free_irq(ts);
319 pdata->exit_platform_hw();
306 err_free_mem: 320 err_free_mem:
307 input_free_device(input_dev); 321 input_free_device(input_dev);
308 kfree(ts); 322 kfree(ts);
309 return err; 323 return err;
310} 324}
311 325
312static int tsc2007_remove(struct i2c_client *client) 326static int __devexit tsc2007_remove(struct i2c_client *client)
313{ 327{
314 struct tsc2007 *ts = i2c_get_clientdata(client); 328 struct tsc2007 *ts = i2c_get_clientdata(client);
315 struct tsc2007_platform_data *pdata; 329 struct tsc2007_platform_data *pdata = client->dev.platform_data;
316 330
317 cancel_delayed_work_sync(&ts->work); 331 tsc2007_free_irq(ts);
318 332
319 pdata = client->dev.platform_data;
320 pdata->exit_platform_hw(); 333 pdata->exit_platform_hw();
321 334
322 free_irq(ts->irq, ts);
323 input_unregister_device(ts->input); 335 input_unregister_device(ts->input);
324 kfree(ts); 336 kfree(ts);
325 337
@@ -340,7 +352,7 @@ static struct i2c_driver tsc2007_driver = {
340 }, 352 },
341 .id_table = tsc2007_idtable, 353 .id_table = tsc2007_idtable,
342 .probe = tsc2007_probe, 354 .probe = tsc2007_probe,
343 .remove = tsc2007_remove, 355 .remove = __devexit_p(tsc2007_remove),
344}; 356};
345 357
346static int __init tsc2007_init(void) 358static int __init tsc2007_init(void)