aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/tsc2007.c
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2009-09-22 19:49:27 -0400
committerAnton Vorontsov <avorontsov@ru.mvista.com>2009-09-22 19:49:27 -0400
commitf056878332a91ed984a116bad4e7d49aefff9e6e (patch)
tree572f4757c8e7811d45e0be0c2ae529c78fb63441 /drivers/input/touchscreen/tsc2007.c
parent3961f7c3cf247eee5df7fabadc7a40f2deeb98f3 (diff)
parent7fa07729e439a6184bd824746d06a49cca553f15 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: drivers/power/wm97xx_battery.c
Diffstat (limited to 'drivers/input/touchscreen/tsc2007.c')
-rw-r--r--drivers/input/touchscreen/tsc2007.c264
1 files changed, 137 insertions, 127 deletions
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 880f58c6a7c..7ef0d1420d3 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -21,15 +21,14 @@
21 */ 21 */
22 22
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/hrtimer.h>
25#include <linux/slab.h> 24#include <linux/slab.h>
26#include <linux/input.h> 25#include <linux/input.h>
27#include <linux/interrupt.h> 26#include <linux/interrupt.h>
28#include <linux/i2c.h> 27#include <linux/i2c.h>
29#include <linux/i2c/tsc2007.h> 28#include <linux/i2c/tsc2007.h>
30 29
31#define TS_POLL_DELAY (10 * 1000) /* ns delay before the first sample */ 30#define TS_POLL_DELAY 1 /* ms delay between samples */
32#define TS_POLL_PERIOD (5 * 1000) /* ns delay between samples */ 31#define TS_POLL_PERIOD 1 /* ms delay between samples */
33 32
34#define TSC2007_MEASURE_TEMP0 (0x0 << 4) 33#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
35#define TSC2007_MEASURE_AUX (0x2 << 4) 34#define TSC2007_MEASURE_AUX (0x2 << 4)
@@ -70,17 +69,14 @@ struct ts_event {
70struct tsc2007 { 69struct tsc2007 {
71 struct input_dev *input; 70 struct input_dev *input;
72 char phys[32]; 71 char phys[32];
73 struct hrtimer timer; 72 struct delayed_work work;
74 struct ts_event tc;
75 73
76 struct i2c_client *client; 74 struct i2c_client *client;
77 75
78 spinlock_t lock;
79
80 u16 model; 76 u16 model;
81 u16 x_plate_ohms; 77 u16 x_plate_ohms;
82 78
83 unsigned pendown; 79 bool pendown;
84 int irq; 80 int irq;
85 81
86 int (*get_pendown_state)(void); 82 int (*get_pendown_state)(void);
@@ -109,52 +105,96 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
109 return val; 105 return val;
110} 106}
111 107
112static void tsc2007_send_event(void *tsc) 108static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
113{ 109{
114 struct tsc2007 *ts = tsc; 110 /* y- still on; turn on only y+ (and ADC) */
115 u32 rt; 111 tc->y = tsc2007_xfer(tsc, READ_Y);
116 u16 x, y, z1, z2; 112
113 /* turn y- off, x+ on, then leave in lowpower */
114 tc->x = tsc2007_xfer(tsc, READ_X);
115
116 /* turn y+ off, x- on; we'll use formula #1 */
117 tc->z1 = tsc2007_xfer(tsc, READ_Z1);
118 tc->z2 = tsc2007_xfer(tsc, READ_Z2);
117 119
118 x = ts->tc.x; 120 /* Prepare for next touch reading - power down ADC, enable PENIRQ */
119 y = ts->tc.y; 121 tsc2007_xfer(tsc, PWRDOWN);
120 z1 = ts->tc.z1; 122}
121 z2 = ts->tc.z2; 123
124static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
125{
126 u32 rt = 0;
122 127
123 /* range filtering */ 128 /* range filtering */
124 if (x == MAX_12BIT) 129 if (tc->x == MAX_12BIT)
125 x = 0; 130 tc->x = 0;
126 131
127 if (likely(x && z1)) { 132 if (likely(tc->x && tc->z1)) {
128 /* compute touch pressure resistance using equation #1 */ 133 /* compute touch pressure resistance using equation #1 */
129 rt = z2; 134 rt = tc->z2 - tc->z1;
130 rt -= z1; 135 rt *= tc->x;
131 rt *= x; 136 rt *= tsc->x_plate_ohms;
132 rt *= ts->x_plate_ohms; 137 rt /= tc->z1;
133 rt /= z1;
134 rt = (rt + 2047) >> 12; 138 rt = (rt + 2047) >> 12;
135 } else 139 }
136 rt = 0; 140
141 return rt;
142}
143
144static void tsc2007_send_up_event(struct tsc2007 *tsc)
145{
146 struct input_dev *input = tsc->input;
137 147
138 /* Sample found inconsistent by debouncing or pressure is beyond 148 dev_dbg(&tsc->client->dev, "UP\n");
139 * the maximum. Don't report it to user space, repeat at least 149
140 * once more the measurement 150 input_report_key(input, BTN_TOUCH, 0);
151 input_report_abs(input, ABS_PRESSURE, 0);
152 input_sync(input);
153}
154
155static void tsc2007_work(struct work_struct *work)
156{
157 struct tsc2007 *ts =
158 container_of(to_delayed_work(work), struct tsc2007, work);
159 struct ts_event tc;
160 u32 rt;
161
162 /*
163 * NOTE: We can't rely on the pressure to determine the pen down
164 * state, even though this controller has a pressure sensor.
165 * The pressure value can fluctuate for quite a while after
166 * lifting the pen and in some cases may not even settle at the
167 * expected value.
168 *
169 * The only safe way to check for the pen up condition is in the
170 * work function by reading the pen signal state (it's a GPIO
171 * and IRQ). Unfortunately such callback is not always available,
172 * in that case we have rely on the pressure anyway.
141 */ 173 */
174 if (ts->get_pendown_state) {
175 if (unlikely(!ts->get_pendown_state())) {
176 tsc2007_send_up_event(ts);
177 ts->pendown = false;
178 goto out;
179 }
180
181 dev_dbg(&ts->client->dev, "pen is still down\n");
182 }
183
184 tsc2007_read_values(ts, &tc);
185
186 rt = tsc2007_calculate_pressure(ts, &tc);
142 if (rt > MAX_12BIT) { 187 if (rt > MAX_12BIT) {
188 /*
189 * Sample found inconsistent by debouncing or pressure is
190 * beyond the maximum. Don't report it to user space,
191 * repeat at least once more the measurement.
192 */
143 dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); 193 dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
194 goto out;
144 195
145 hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
146 HRTIMER_MODE_REL);
147 return;
148 } 196 }
149 197
150 /* NOTE: We can't rely on the pressure to determine the pen down
151 * state, even this controller has a pressure sensor. The pressure
152 * value can fluctuate for quite a while after lifting the pen and
153 * in some cases may not even settle at the expected value.
154 *
155 * The only safe way to check for the pen up condition is in the
156 * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
157 */
158 if (rt) { 198 if (rt) {
159 struct input_dev *input = ts->input; 199 struct input_dev *input = ts->input;
160 200
@@ -162,102 +202,74 @@ static void tsc2007_send_event(void *tsc)
162 dev_dbg(&ts->client->dev, "DOWN\n"); 202 dev_dbg(&ts->client->dev, "DOWN\n");
163 203
164 input_report_key(input, BTN_TOUCH, 1); 204 input_report_key(input, BTN_TOUCH, 1);
165 ts->pendown = 1; 205 ts->pendown = true;
166 } 206 }
167 207
168 input_report_abs(input, ABS_X, x); 208 input_report_abs(input, ABS_X, tc.x);
169 input_report_abs(input, ABS_Y, y); 209 input_report_abs(input, ABS_Y, tc.y);
170 input_report_abs(input, ABS_PRESSURE, rt); 210 input_report_abs(input, ABS_PRESSURE, rt);
171 211
172 input_sync(input); 212 input_sync(input);
173 213
174 dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", 214 dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
175 x, y, rt); 215 tc.x, tc.y, rt);
216
217 } else if (!ts->get_pendown_state && ts->pendown) {
218 /*
219 * We don't have callback to check pendown state, so we
220 * have to assume that since pressure reported is 0 the
221 * pen was lifted up.
222 */
223 tsc2007_send_up_event(ts);
224 ts->pendown = false;
176 } 225 }
177 226
178 hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), 227 out:
179 HRTIMER_MODE_REL); 228 if (ts->pendown)
180} 229 schedule_delayed_work(&ts->work,
181 230 msecs_to_jiffies(TS_POLL_PERIOD));
182static int tsc2007_read_values(struct tsc2007 *tsc) 231 else
183{
184 /* y- still on; turn on only y+ (and ADC) */
185 tsc->tc.y = tsc2007_xfer(tsc, READ_Y);
186
187 /* turn y- off, x+ on, then leave in lowpower */
188 tsc->tc.x = tsc2007_xfer(tsc, READ_X);
189
190 /* turn y+ off, x- on; we'll use formula #1 */
191 tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1);
192 tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2);
193
194 /* power down */
195 tsc2007_xfer(tsc, PWRDOWN);
196
197 return 0;
198}
199
200static enum hrtimer_restart tsc2007_timer(struct hrtimer *handle)
201{
202 struct tsc2007 *ts = container_of(handle, struct tsc2007, timer);
203 unsigned long flags;
204
205 spin_lock_irqsave(&ts->lock, flags);
206
207 if (unlikely(!ts->get_pendown_state() && ts->pendown)) {
208 struct input_dev *input = ts->input;
209
210 dev_dbg(&ts->client->dev, "UP\n");
211
212 input_report_key(input, BTN_TOUCH, 0);
213 input_report_abs(input, ABS_PRESSURE, 0);
214 input_sync(input);
215
216 ts->pendown = 0;
217 enable_irq(ts->irq); 232 enable_irq(ts->irq);
218 } else {
219 /* pen is still down, continue with the measurement */
220 dev_dbg(&ts->client->dev, "pen is still down\n");
221
222 tsc2007_read_values(ts);
223 tsc2007_send_event(ts);
224 }
225
226 spin_unlock_irqrestore(&ts->lock, flags);
227
228 return HRTIMER_NORESTART;
229} 233}
230 234
231static irqreturn_t tsc2007_irq(int irq, void *handle) 235static irqreturn_t tsc2007_irq(int irq, void *handle)
232{ 236{
233 struct tsc2007 *ts = handle; 237 struct tsc2007 *ts = handle;
234 unsigned long flags;
235
236 spin_lock_irqsave(&ts->lock, flags);
237 238
238 if (likely(ts->get_pendown_state())) { 239 if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
239 disable_irq_nosync(ts->irq); 240 disable_irq_nosync(ts->irq);
240 hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), 241 schedule_delayed_work(&ts->work,
241 HRTIMER_MODE_REL); 242 msecs_to_jiffies(TS_POLL_DELAY));
242 } 243 }
243 244
244 if (ts->clear_penirq) 245 if (ts->clear_penirq)
245 ts->clear_penirq(); 246 ts->clear_penirq();
246 247
247 spin_unlock_irqrestore(&ts->lock, flags);
248
249 return IRQ_HANDLED; 248 return IRQ_HANDLED;
250} 249}
251 250
252static int tsc2007_probe(struct i2c_client *client, 251static void tsc2007_free_irq(struct tsc2007 *ts)
253 const struct i2c_device_id *id) 252{
253 free_irq(ts->irq, ts);
254 if (cancel_delayed_work_sync(&ts->work)) {
255 /*
256 * Work was pending, therefore we need to enable
257 * IRQ here to balance the disable_irq() done in the
258 * interrupt handler.
259 */
260 enable_irq(ts->irq);
261 }
262}
263
264static int __devinit tsc2007_probe(struct i2c_client *client,
265 const struct i2c_device_id *id)
254{ 266{
255 struct tsc2007 *ts; 267 struct tsc2007 *ts;
256 struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data; 268 struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;
257 struct input_dev *input_dev; 269 struct input_dev *input_dev;
258 int err; 270 int err;
259 271
260 if (!pdata || !pdata->get_pendown_state) { 272 if (!pdata) {
261 dev_err(&client->dev, "platform data is required!\n"); 273 dev_err(&client->dev, "platform data is required!\n");
262 return -EINVAL; 274 return -EINVAL;
263 } 275 }
@@ -274,22 +286,15 @@ static int tsc2007_probe(struct i2c_client *client,
274 } 286 }
275 287
276 ts->client = client; 288 ts->client = client;
277 i2c_set_clientdata(client, ts); 289 ts->irq = client->irq;
278
279 ts->input = input_dev; 290 ts->input = input_dev;
280 291 INIT_DELAYED_WORK(&ts->work, tsc2007_work);
281 hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
282 ts->timer.function = tsc2007_timer;
283
284 spin_lock_init(&ts->lock);
285 292
286 ts->model = pdata->model; 293 ts->model = pdata->model;
287 ts->x_plate_ohms = pdata->x_plate_ohms; 294 ts->x_plate_ohms = pdata->x_plate_ohms;
288 ts->get_pendown_state = pdata->get_pendown_state; 295 ts->get_pendown_state = pdata->get_pendown_state;
289 ts->clear_penirq = pdata->clear_penirq; 296 ts->clear_penirq = pdata->clear_penirq;
290 297
291 pdata->init_platform_hw();
292
293 snprintf(ts->phys, sizeof(ts->phys), 298 snprintf(ts->phys, sizeof(ts->phys),
294 "%s/input0", dev_name(&client->dev)); 299 "%s/input0", dev_name(&client->dev));
295 300
@@ -304,9 +309,8 @@ static int tsc2007_probe(struct i2c_client *client,
304 input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); 309 input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
305 input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0); 310 input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
306 311
307 tsc2007_read_values(ts); 312 if (pdata->init_platform_hw)
308 313 pdata->init_platform_hw();
309 ts->irq = client->irq;
310 314
311 err = request_irq(ts->irq, tsc2007_irq, 0, 315 err = request_irq(ts->irq, tsc2007_irq, 0,
312 client->dev.driver->name, ts); 316 client->dev.driver->name, ts);
@@ -315,33 +319,39 @@ static int tsc2007_probe(struct i2c_client *client,
315 goto err_free_mem; 319 goto err_free_mem;
316 } 320 }
317 321
322 /* Prepare for touch readings - power down ADC and enable PENIRQ */
323 err = tsc2007_xfer(ts, PWRDOWN);
324 if (err < 0)
325 goto err_free_irq;
326
318 err = input_register_device(input_dev); 327 err = input_register_device(input_dev);
319 if (err) 328 if (err)
320 goto err_free_irq; 329 goto err_free_irq;
321 330
322 dev_info(&client->dev, "registered with irq (%d)\n", ts->irq); 331 i2c_set_clientdata(client, ts);
323 332
324 return 0; 333 return 0;
325 334
326 err_free_irq: 335 err_free_irq:
327 free_irq(ts->irq, ts); 336 tsc2007_free_irq(ts);
328 hrtimer_cancel(&ts->timer); 337 if (pdata->exit_platform_hw)
338 pdata->exit_platform_hw();
329 err_free_mem: 339 err_free_mem:
330 input_free_device(input_dev); 340 input_free_device(input_dev);
331 kfree(ts); 341 kfree(ts);
332 return err; 342 return err;
333} 343}
334 344
335static int tsc2007_remove(struct i2c_client *client) 345static int __devexit tsc2007_remove(struct i2c_client *client)
336{ 346{
337 struct tsc2007 *ts = i2c_get_clientdata(client); 347 struct tsc2007 *ts = i2c_get_clientdata(client);
338 struct tsc2007_platform_data *pdata; 348 struct tsc2007_platform_data *pdata = client->dev.platform_data;
339 349
340 pdata = client->dev.platform_data; 350 tsc2007_free_irq(ts);
341 pdata->exit_platform_hw(); 351
352 if (pdata->exit_platform_hw)
353 pdata->exit_platform_hw();
342 354
343 free_irq(ts->irq, ts);
344 hrtimer_cancel(&ts->timer);
345 input_unregister_device(ts->input); 355 input_unregister_device(ts->input);
346 kfree(ts); 356 kfree(ts);
347 357
@@ -362,7 +372,7 @@ static struct i2c_driver tsc2007_driver = {
362 }, 372 },
363 .id_table = tsc2007_idtable, 373 .id_table = tsc2007_idtable,
364 .probe = tsc2007_probe, 374 .probe = tsc2007_probe,
365 .remove = tsc2007_remove, 375 .remove = __devexit_p(tsc2007_remove),
366}; 376};
367 377
368static int __init tsc2007_init(void) 378static int __init tsc2007_init(void)