aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2009-08-05 01:07:26 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2009-08-05 01:35:34 -0400
commitd570e9ef84e559b09e729f27f5381b6868f6cc5f (patch)
tree970edd1959e4042ea0e04d39a969f818155867e0 /drivers/input/touchscreen
parent9e3b25837a20f4d48fef57b0cb8bf750a8cfa8e2 (diff)
Input: tsc2007 - make get_pendown_state platform callback optional
In cases when get_pendown_state callback is not available have the driver to fallback on pressure calculation to determine if the pen is up. Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r--drivers/input/touchscreen/tsc2007.c172
1 files changed, 93 insertions, 79 deletions
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index f710af4d0ff7..3714d19f1027 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -70,7 +70,6 @@ struct tsc2007 {
70 struct input_dev *input; 70 struct input_dev *input;
71 char phys[32]; 71 char phys[32];
72 struct delayed_work work; 72 struct delayed_work work;
73 struct ts_event tc;
74 73
75 struct i2c_client *client; 74 struct i2c_client *client;
76 75
@@ -106,51 +105,96 @@ static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
106 return val; 105 return val;
107} 106}
108 107
109static void tsc2007_send_event(void *tsc) 108static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
110{ 109{
111 struct tsc2007 *ts = tsc; 110 /* y- still on; turn on only y+ (and ADC) */
112 u32 rt; 111 tc->y = tsc2007_xfer(tsc, READ_Y);
113 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);
114 119
115 x = ts->tc.x; 120 /* Prepare for next touch reading - power down ADC, enable PENIRQ */
116 y = ts->tc.y; 121 tsc2007_xfer(tsc, PWRDOWN);
117 z1 = ts->tc.z1; 122}
118 z2 = ts->tc.z2; 123
124static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)
125{
126 u32 rt = 0;
119 127
120 /* range filtering */ 128 /* range filtering */
121 if (x == MAX_12BIT) 129 if (tc->x == MAX_12BIT)
122 x = 0; 130 tc->x = 0;
123 131
124 if (likely(x && z1)) { 132 if (likely(tc->x && tc->z1)) {
125 /* compute touch pressure resistance using equation #1 */ 133 /* compute touch pressure resistance using equation #1 */
126 rt = z2; 134 rt = tc->z2 - tc->z1;
127 rt -= z1; 135 rt *= tc->x;
128 rt *= x; 136 rt *= tsc->x_plate_ohms;
129 rt *= ts->x_plate_ohms; 137 rt /= tc->z1;
130 rt /= z1;
131 rt = (rt + 2047) >> 12; 138 rt = (rt + 2047) >> 12;
132 } else
133 rt = 0;
134
135 /*
136 * Sample found inconsistent by debouncing or pressure is beyond
137 * the maximum. Don't report it to user space, repeat at least
138 * once more the measurement
139 */
140 if (rt > MAX_12BIT) {
141 dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
142 return;
143 } 139 }
144 140
141 return rt;
142}
143
144static void tsc2007_send_up_event(struct tsc2007 *tsc)
145{
146 struct input_dev *input = tsc->input;
147
148 dev_dbg(&tsc->client->dev, "UP\n");
149
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
145 /* 162 /*
146 * NOTE: We can't rely on the pressure to determine the pen down 163 * NOTE: We can't rely on the pressure to determine the pen down
147 * state, even this controller has a pressure sensor. The pressure 164 * state, even though this controller has a pressure sensor.
148 * value can fluctuate for quite a while after lifting the pen and 165 * The pressure value can fluctuate for quite a while after
149 * in some cases may not even settle at the expected value. 166 * lifting the pen and in some cases may not even settle at the
167 * expected value.
150 * 168 *
151 * The only safe way to check for the pen up condition is in the 169 * The only safe way to check for the pen up condition is in the
152 * work function by reading the pen signal state (it's a GPIO and IRQ). 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.
153 */ 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);
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 */
193 dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
194 goto out;
195
196 }
197
154 if (rt) { 198 if (rt) {
155 struct input_dev *input = ts->input; 199 struct input_dev *input = ts->input;
156 200
@@ -161,68 +205,38 @@ static void tsc2007_send_event(void *tsc)
161 ts->pendown = true; 205 ts->pendown = true;
162 } 206 }
163 207
164 input_report_abs(input, ABS_X, x); 208 input_report_abs(input, ABS_X, tc.x);
165 input_report_abs(input, ABS_Y, y); 209 input_report_abs(input, ABS_Y, tc.y);
166 input_report_abs(input, ABS_PRESSURE, rt); 210 input_report_abs(input, ABS_PRESSURE, rt);
167 211
168 input_sync(input); 212 input_sync(input);
169 213
170 dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n", 214 dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)\n",
171 x, y, rt); 215 tc.x, tc.y, rt);
172 }
173}
174
175static int tsc2007_read_values(struct tsc2007 *tsc)
176{
177 /* y- still on; turn on only y+ (and ADC) */
178 tsc->tc.y = tsc2007_xfer(tsc, READ_Y);
179
180 /* turn y- off, x+ on, then leave in lowpower */
181 tsc->tc.x = tsc2007_xfer(tsc, READ_X);
182
183 /* turn y+ off, x- on; we'll use formula #1 */
184 tsc->tc.z1 = tsc2007_xfer(tsc, READ_Z1);
185 tsc->tc.z2 = tsc2007_xfer(tsc, READ_Z2);
186
187 /* Prepare for next touch reading - power down ADC, enable PENIRQ */
188 tsc2007_xfer(tsc, PWRDOWN);
189
190 return 0;
191}
192
193static void tsc2007_work(struct work_struct *work)
194{
195 struct tsc2007 *ts =
196 container_of(to_delayed_work(work), struct tsc2007, work);
197
198 if (unlikely(!ts->get_pendown_state() && ts->pendown)) {
199 struct input_dev *input = ts->input;
200
201 dev_dbg(&ts->client->dev, "UP\n");
202
203 input_report_key(input, BTN_TOUCH, 0);
204 input_report_abs(input, ABS_PRESSURE, 0);
205 input_sync(input);
206 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);
207 ts->pendown = false; 224 ts->pendown = false;
208 enable_irq(ts->irq); 225 }
209 } else {
210 /* pen is still down, continue with the measurement */
211 dev_dbg(&ts->client->dev, "pen is still down\n");
212
213 tsc2007_read_values(ts);
214 tsc2007_send_event(ts);
215 226
227 out:
228 if (ts->pendown)
216 schedule_delayed_work(&ts->work, 229 schedule_delayed_work(&ts->work,
217 msecs_to_jiffies(TS_POLL_PERIOD)); 230 msecs_to_jiffies(TS_POLL_PERIOD));
218 } 231 else
232 enable_irq(ts->irq);
219} 233}
220 234
221static irqreturn_t tsc2007_irq(int irq, void *handle) 235static irqreturn_t tsc2007_irq(int irq, void *handle)
222{ 236{
223 struct tsc2007 *ts = handle; 237 struct tsc2007 *ts = handle;
224 238
225 if (likely(ts->get_pendown_state())) { 239 if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
226 disable_irq_nosync(ts->irq); 240 disable_irq_nosync(ts->irq);
227 schedule_delayed_work(&ts->work, 241 schedule_delayed_work(&ts->work,
228 msecs_to_jiffies(TS_POLL_DELAY)); 242 msecs_to_jiffies(TS_POLL_DELAY));
@@ -255,7 +269,7 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
255 struct input_dev *input_dev; 269 struct input_dev *input_dev;
256 int err; 270 int err;
257 271
258 if (!pdata || !pdata->get_pendown_state) { 272 if (!pdata) {
259 dev_err(&client->dev, "platform data is required!\n"); 273 dev_err(&client->dev, "platform data is required!\n");
260 return -EINVAL; 274 return -EINVAL;
261 } 275 }