aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@mail.ru>2010-09-01 01:57:28 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-09-01 22:43:08 -0400
commit95b7127c1141bddd3cff30415c7d6e656f335a35 (patch)
treee715bc6002139fd021fb14fdff5e0f9d5ac26b70
parentaff4c343614f0c9980352810df70969821cba95f (diff)
Staging: mrst_touchscreen - more fixes
Changes: - switch to use threaded IRQ - more __devinit/__devexit annotations - rely on input core to remove jitter from events - global pointer removed - NEC/MAXIM/Freescale handling factored out Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/staging/mrst-touchscreen/intel-mid-touch.c892
1 files changed, 413 insertions, 479 deletions
diff --git a/drivers/staging/mrst-touchscreen/intel-mid-touch.c b/drivers/staging/mrst-touchscreen/intel-mid-touch.c
index 6fed01ee82d..be7ba7b4759 100644
--- a/drivers/staging/mrst-touchscreen/intel-mid-touch.c
+++ b/drivers/staging/mrst-touchscreen/intel-mid-touch.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * intel_mid_touch.c - Intel MID Resistive Touch Screen Driver 2 * Intel MID Resistive Touch Screen Driver
3 * 3 *
4 * Copyright (C) 2008 Intel Corp 4 * Copyright (C) 2008 Intel Corp
5 * 5 *
@@ -15,18 +15,15 @@
15 * General Public License for more details. 15 * General Public License for more details.
16 * 16 *
17 * You should have received a copy of the GNU General Public License along 17 * You should have received a copy of the GNU General Public License along
18 * with this program; ifnot, write to the Free Software Foundation, Inc., 18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 * 20 *
21 * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com) 21 * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
22 * Ramesh Agarwal (ramesh.agarwal@intel.com) 22 * Ramesh Agarwal (ramesh.agarwal@intel.com)
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 * 24 *
25 * TODO: 25 * TODO:
26 * review conversion of r/m/w sequences 26 * review conversion of r/m/w sequences
27 * Replace interrupt mutex abuse
28 * Kill of mrstouchdevp pointer
29 *
30 */ 27 */
31 28
32#include <linux/module.h> 29#include <linux/module.h>
@@ -38,158 +35,104 @@
38#include <linux/spi/spi.h> 35#include <linux/spi/spi.h>
39#include <linux/irq.h> 36#include <linux/irq.h>
40#include <linux/delay.h> 37#include <linux/delay.h>
41#include <linux/kthread.h>
42#include <asm/intel_scu_ipc.h> 38#include <asm/intel_scu_ipc.h>
43 39
44
45/* PMIC Interrupt registers */ 40/* PMIC Interrupt registers */
46#define PMIC_REG_ID1 0x00 /*PMIC ID1 register */ 41#define PMIC_REG_ID1 0x00 /* PMIC ID1 register */
47 42
48/* PMIC Interrupt registers */ 43/* PMIC Interrupt registers */
49#define PMIC_REG_INT 0x04 /*PMIC interrupt register */ 44#define PMIC_REG_INT 0x04 /* PMIC interrupt register */
50#define PMIC_REG_MINT 0x05 /*PMIC interrupt mask register */ 45#define PMIC_REG_MINT 0x05 /* PMIC interrupt mask register */
51 46
52/* ADC Interrupt registers */ 47/* ADC Interrupt registers */
53#define PMIC_REG_ADCINT 0x5F /*ADC interrupt register */ 48#define PMIC_REG_ADCINT 0x5F /* ADC interrupt register */
54#define PMIC_REG_MADCINT 0x60 /*ADC interrupt mask register */ 49#define PMIC_REG_MADCINT 0x60 /* ADC interrupt mask register */
55 50
56/* ADC Control registers */ 51/* ADC Control registers */
57#define PMIC_REG_ADCCNTL1 0x61 /*ADC control register */ 52#define PMIC_REG_ADCCNTL1 0x61 /* ADC control register */
58 53
59/* ADC Channel Selection registers */ 54/* ADC Channel Selection registers */
60#define PMICADDR0 0xA4 55#define PMICADDR0 0xA4
61#define END_OF_CHANNEL 0x1F 56#define END_OF_CHANNEL 0x1F
62 57
63/* ADC Result register */ 58/* ADC Result register */
64#define PMIC_REG_ADCSNS0H 0x64 59#define PMIC_REG_ADCSNS0H 0x64
65 60
66/* ADC channels for touch screen */ 61/* ADC channels for touch screen */
67#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */ 62#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
68#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */ 63#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
69#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */ 64#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
70#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */ 65#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
71
72/* Touch screen coordinate constants */
73#define TOUCH_PRESSURE 50
74#define TOUCH_PRESSURE_FS 100
75
76#define XMOVE_LIMIT 5
77#define YMOVE_LIMIT 5
78#define XYMOVE_CNT 3
79
80#define MAX_10BIT ((1<<10)-1)
81 66
82/* Touch screen channel BIAS constants */ 67/* Touch screen channel BIAS constants */
83#define XBIAS 0x20 68#define MRST_XBIAS 0x20
84#define YBIAS 0x40 69#define MRST_YBIAS 0x40
85#define ZBIAS 0x80 70#define MRST_ZBIAS 0x80
86 71
87/* Touch screen coordinates */ 72/* Touch screen coordinates */
88#define MIN_X 10 73#define MRST_X_MIN 10
89#define MAX_X 1024 74#define MRST_X_MAX 1024
90#define MIN_Y 10 75#define MRST_X_FUZZ 5
91#define MAX_Y 1024 76#define MRST_Y_MIN 10
92#define MIN_P 0 77#define MRST_Y_MAX 1024
93#define MAX_P TOUCH_PRESSURE_FS 78#define MRST_Y_FUZZ 5
94 79#define MRST_PRESSURE_MIN 0
95#define WAIT_ADC_COMPLETION 10 80#define MRST_PRESSURE_NOMINAL 50
81#define MRST_PRESSURE_MAX 100
82
83#define WAIT_ADC_COMPLETION 10 /* msec */
96 84
97/* PMIC ADC round robin delays */ 85/* PMIC ADC round robin delays */
98#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */ 86#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
99#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */ 87#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
100 88
101/* PMIC Vendor Identifiers */ 89/* PMIC Vendor Identifiers */
102#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */ 90#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
103#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */ 91#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
104#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */ 92#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
105#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */ 93#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
106 94
107/* Touch screen device structure */ 95/* Touch screen device structure */
108struct mrstouch_dev { 96struct mrstouch_dev {
109 struct spi_device *spi; /* SPI device associated with touch screen */ 97 struct spi_device *spi;
110 struct input_dev *input; /* input device for touchscreen*/ 98 struct input_dev *input;
111 char phys[32]; /* Device name */ 99 char phys[32];
112 struct task_struct *pendet_thrd; /* PENDET interrupt handler */ 100 u16 asr; /* Address selection register */
113 struct mutex lock; /* Sync between interrupt and PENDET handler */ 101 int irq;
114 bool busy; /* Busy flag */ 102 unsigned int vendor; /* PMIC vendor */
115 u16 asr; /* Address selection register */ 103 unsigned int rev; /* PMIC revision */
116 int irq; /* Touch screen IRQ # */ 104
117 uint vendor; /* PMIC vendor */ 105 int (*read_prepare)(struct mrstouch_dev *tsdev);
118 uint rev; /* PMIC revision */ 106 int (*read)(struct mrstouch_dev *tsdev, u16 *x, u16 *y, u16 *z);
119 u16 x; /* X coordinate */ 107 int (*read_finish)(struct mrstouch_dev *tsdev);
120 u16 y; /* Y coordinate */ 108};
121 bool pendown; /* PEN position */
122} ;
123
124
125/* Global Pointer to Touch screen device */
126static struct mrstouch_dev *mrstouchdevp;
127 109
128/* Utility to read PMIC ID */ 110
129static int mrstouch_pmic_id(uint *vendor, uint *rev) 111/*************************** NEC and Maxim Interface ************************/
112
113static int mrstouch_nec_adc_read_prepare(struct mrstouch_dev *tsdev)
130{ 114{
115 u16 reg;
131 int err; 116 int err;
132 u8 r;
133 117
134 err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r); 118 err = intel_scu_ipc_ioread16(PMIC_REG_MADCINT, &reg);
135 if (err) 119 if (err)
136 return err; 120 return err;
137 121
138 *vendor = r & 0x7; 122 reg &= 0xDFFF; /* Disable pendet */
139 *rev = (r >> 3) & 0x7;
140 123
141 return 0; 124 /* Set MADCINT and update ADCCNTL1 (next reg byte) */
125 return intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg);
142} 126}
143 127
144/* 128/*
145 * Parse ADC channels to find end of the channel configured by other ADC user 129 * Enables PENDET interrupt.
146 * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
147 */ 130 */
148static int mrstouch_chan_parse(struct mrstouch_dev *tsdev) 131static int mrstouch_nec_adc_read_finish(struct mrstouch_dev *tsdev)
149{
150 int err, i, j, found;
151 u32 r32;
152
153 found = -1;
154
155 for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
156 if (found >= 0)
157 break;
158
159 err = intel_scu_ipc_ioread32(PMICADDR0, &r32);
160 if (err)
161 return err;
162
163 for (j = 0; j < 32; j+= 8) {
164 if (((r32 >> j) & 0xFF) == END_OF_CHANNEL) {
165 found = i;
166 break;
167 }
168 }
169 }
170 if (found < 0)
171 return 0;
172
173 if (tsdev->vendor == PMIC_VENDOR_FS) {
174 if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
175 return -ENOSPC;
176 } else {
177 if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
178 return -ENOSPC;
179 }
180 return found;
181}
182
183/* Utility to enable/disable pendet.
184 * pendet set to true enables PENDET interrupt
185 * pendet set to false disables PENDET interrupt
186 * Also clears RND mask bit
187*/
188static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet)
189{ 132{
190 u16 reg; 133 u16 reg;
191 u8 r; 134 u8 r;
192 u8 pendet_enabled = 0; 135 u8 pendet_enabled;
193 int retry = 0; 136 int retry = 0;
194 int err; 137 int err;
195 138
@@ -197,15 +140,12 @@ static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet)
197 if (err) 140 if (err)
198 return err; 141 return err;
199 142
200 if (pendet) { 143 reg &= ~0x0005;
201 reg &= ~0x0005; 144 reg |= 0x2000; /* Enable pendet */
202 reg |= 0x2000; /* Enable pendet */
203 } else
204 reg &= 0xDFFF; /* Disable pendet */
205 145
206 /* Set MADCINT and update ADCCNTL1 (next reg byte) */ 146 /* Set MADCINT and update ADCCNTL1 (next reg byte) */
207 err = intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg); 147 err = intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg);
208 if (!pendet || err) 148 if (err)
209 return err; 149 return err;
210 150
211 /* 151 /*
@@ -213,31 +153,36 @@ static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet)
213 * the PMIC register value is not updated. Retry few iterations 153 * the PMIC register value is not updated. Retry few iterations
214 * to enable pendet. 154 * to enable pendet.
215 */ 155 */
156 do {
157 err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
158 if (err)
159 return err;
216 160
217 err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r); 161 pendet_enabled = (r >> 5) & 0x01;
218 pendet_enabled = (r >> 5) & 0x01;
219 162
220 retry = 0; 163 if (!pendet_enabled) {
221 while (!err && !pendet_enabled) { 164 if (++retry >= 10) {
222 retry++; 165 dev_err(&tsdev->spi->dev,
223 msleep(10); 166 "Touch screen disabled.\n");
224 err = intel_scu_ipc_iowrite8(PMIC_REG_ADCCNTL1, reg >> 8); 167 return -EIO;
225 if (err) 168 }
226 break; 169
227 err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r); 170 msleep(10);
228 if (err == 0) 171
229 pendet_enabled = (r >> 5) & 0x01; 172 err = intel_scu_ipc_iowrite8(PMIC_REG_ADCCNTL1,
230 if (retry >= 10) { 173 reg >> 8);
231 dev_err(&tsdev->spi->dev, "Touch screen disabled.\n"); 174 if (err)
232 return -EIO; 175 return err;
233 } 176 }
234 } 177 } while (!pendet_enabled);
178
235 return 0; 179 return 0;
236} 180}
237 181
238/* To read PMIC ADC touch screen result 182/*
239 * Reads ADC storage registers for higher 7 and lower 3 bits 183 * Reads PMIC ADC touch screen result
240 * converts the two readings to single value and turns off gain bit 184 * Reads ADC storage registers for higher 7 and lower 3 bits and
185 * converts the two readings into a single value and turns off gain bit
241 */ 186 */
242static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm) 187static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
243{ 188{
@@ -269,187 +214,93 @@ static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
269 return 0; 214 return 0;
270} 215}
271 216
272/* To configure touch screen channels 217/*
273 * Writes touch screen channels to ADC address selection registers 218 * Enables X, Y and Z bias values
219 * Enables YPYM for X channels and XPXM for Y channels
274 */ 220 */
275static int mrstouch_ts_chan_set(uint offset) 221static int mrstouch_ts_bias_set(uint offset, uint bias)
276{ 222{
277 int count; 223 int count;
278 u16 chan; 224 u16 chan, start;
279 u16 reg[5]; 225 u16 reg[4];
280 u8 data[5]; 226 u8 data[4];
281 227
282 chan = PMICADDR0 + offset; 228 chan = PMICADDR0 + offset;
229 start = MRST_TS_CHAN10;
230
283 for (count = 0; count <= 3; count++) { 231 for (count = 0; count <= 3; count++) {
284 reg[count] = chan++; 232 reg[count] = chan++;
285 data[count] = MRST_TS_CHAN10 + count; 233 data[count] = bias | (start + count);
286 }
287 reg[count] = chan;
288 data[count] = END_OF_CHANNEL;
289
290 return intel_scu_ipc_writev(reg, data, 5);
291}
292
293/* Initialize ADC */
294static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
295{
296 int err, start;
297 u8 ra, rm;
298
299 err = mrstouch_pmic_id(&tsdev->vendor, &tsdev->rev);
300 if (err) {
301 dev_err(&tsdev->spi->dev, "Unable to read PMIC id\n");
302 return err;
303 }
304
305 start = mrstouch_chan_parse(tsdev);
306 if (start < 0) {
307 dev_err(&tsdev->spi->dev, "Unable to parse channels\n");
308 return start;
309 }
310
311 tsdev->asr = start;
312
313 /* ADC power on, start, enable PENDET and set loop delay
314 * ADC loop delay is set to 4.5 ms approximately
315 * Loop delay more than this results in jitter in adc readings
316 * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
317 * interrupt generation sometimes.
318 */
319
320 if (tsdev->vendor == PMIC_VENDOR_FS) {
321 ra = 0xE0 | ADC_LOOP_DELAY0;
322 rm = 0x5;
323 } else {
324 /* NEC and MAXIm not consistent with loop delay 0 */
325 ra = 0xE0 | ADC_LOOP_DELAY1;
326 rm = 0x0;
327
328 /* configure touch screen channels */
329 err = mrstouch_ts_chan_set(tsdev->asr);
330 if (err)
331 return err;
332 }
333 err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
334 if (err == 0)
335 err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
336 return err;
337}
338
339/* Reports x,y coordinates to event subsystem */
340static void mrstouch_report_xy(struct mrstouch_dev *tsdev, u16 x, u16 y, u16 z)
341{
342 int xdiff, ydiff;
343
344 if (tsdev->pendown && z <= TOUCH_PRESSURE) {
345 /* Pen removed, report button release */
346 input_report_key(tsdev->input, BTN_TOUCH, 0);
347 tsdev->pendown = false;
348 }
349
350 xdiff = abs(x - tsdev->x);
351 ydiff = abs(y - tsdev->y);
352
353 /*
354 if x and y values changes for XYMOVE_CNT readings it is considered
355 as stylus is moving. This is required to differentiate between stylus
356 movement and jitter
357 */
358 if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) {
359 /* Spurious values, release button if touched and return */
360 if (tsdev->pendown) {
361 input_report_key(tsdev->input, BTN_TOUCH, 0);
362 tsdev->pendown = false;
363 }
364 return;
365 } else if (xdiff >= XMOVE_LIMIT || ydiff >= YMOVE_LIMIT) {
366 tsdev->x = x;
367 tsdev->y = y;
368
369 input_report_abs(tsdev->input, ABS_X, x);
370 input_report_abs(tsdev->input, ABS_Y, y);
371 input_report_abs(tsdev->input, ABS_PRESSURE, z);
372 input_sync(tsdev->input);
373 } 234 }
374 235
375 236 return intel_scu_ipc_writev(reg, data, 4);
376 if (!tsdev->pendown && z > TOUCH_PRESSURE) {
377 /* Pen touched, report button touch */
378 input_report_key(tsdev->input, BTN_TOUCH, 1);
379 tsdev->pendown = true;
380 }
381}
382
383
384/* Utility to start ADC, used by freescale handler */
385static int pendet_mask(void)
386{
387 return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
388}
389
390/* Utility to stop ADC, used by freescale handler */
391static int pendet_umask(void)
392{
393 return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
394} 237}
395 238
396/* Utility to read ADC, used by freescale handler */ 239/* To read touch screen channel values */
397static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev) 240static int mrstouch_nec_adc_read(struct mrstouch_dev *tsdev,
241 u16 *x, u16 *y, u16 *z)
398{ 242{
399 int err; 243 int err;
400 u16 x, y, z, result; 244 u16 xm, ym, zm;
401 u16 reg[4];
402 u8 data[4];
403 245
404 result = PMIC_REG_ADCSNS0H + tsdev->asr; 246 /* configure Y bias for X channels */
247 err = mrstouch_ts_bias_set(tsdev->asr, MRST_YBIAS);
248 if (err)
249 goto ipc_error;
405 250
406 reg[0] = result + 4; 251 msleep(WAIT_ADC_COMPLETION);
407 reg[1] = result + 5;
408 reg[2] = result + 16;
409 reg[3] = result + 17;
410 252
411 err = intel_scu_ipc_readv(reg, data, 4); 253 /* read x+ and x- channels */
254 err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, x, &xm);
412 if (err) 255 if (err)
413 goto ipc_error; 256 goto ipc_error;
414 257
415 x = data[0] << 3; /* Higher 7 bits */ 258 /* configure x bias for y channels */
416 x |= data[1] & 0x7; /* Lower 3 bits */ 259 err = mrstouch_ts_bias_set(tsdev->asr, MRST_XBIAS);
417 x &= 0x3FF; 260 if (err)
261 goto ipc_error;
418 262
419 y = data[2] << 3; /* Higher 7 bits */ 263 msleep(WAIT_ADC_COMPLETION);
420 y |= data[3] & 0x7; /* Lower 3 bits */
421 y &= 0x3FF;
422 264
423 /* Read Z value */ 265 /* read y+ and y- channels */
424 reg[0] = result + 28; 266 err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, y, &ym);
425 reg[1] = result + 29; 267 if (err)
268 goto ipc_error;
426 269
427 err = intel_scu_ipc_readv(reg, data, 4); 270 /* configure z bias for x and y channels */
271 err = mrstouch_ts_bias_set(tsdev->asr, MRST_ZBIAS);
428 if (err) 272 if (err)
429 goto ipc_error; 273 goto ipc_error;
430 274
431 z = data[0] << 3; /* Higher 7 bits */ 275 msleep(WAIT_ADC_COMPLETION);
432 z |= data[1] & 0x7; /* Lower 3 bits */ 276
433 z &= 0x3FF; 277 /* read z+ and z- channels */
278 err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, z, &zm);
279 if (err)
280 goto ipc_error;
434 281
435 mrstouch_report_xy(tsdev, x, y, z);
436 return 0; 282 return 0;
437 283
438ipc_error: 284ipc_error:
439 dev_err(&tsdev->spi->dev, "ipc error during fs_adc read\n"); 285 dev_err(&tsdev->spi->dev, "ipc error during adc read\n");
440 return err; 286 return err;
441} 287}
442 288
443/* To handle free scale pmic pendet interrupt */ 289
444static int pmic0_pendet(void *dev_id) 290/*************************** Freescale Interface ************************/
291
292static int mrstouch_fs_adc_read_prepare(struct mrstouch_dev *tsdev)
445{ 293{
446 int err, count; 294 int err, count;
447 u16 chan; 295 u16 chan;
448 unsigned int touched;
449 struct mrstouch_dev *tsdev = (struct mrstouch_dev *)dev_id;
450 u16 reg[5]; 296 u16 reg[5];
451 u8 data[5]; 297 u8 data[5];
452 298
299 /* Stop the ADC */
300 err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
301 if (err)
302 goto ipc_error;
303
453 chan = PMICADDR0 + tsdev->asr; 304 chan = PMICADDR0 + tsdev->asr;
454 305
455 /* Set X BIAS */ 306 /* Set X BIAS */
@@ -487,16 +338,65 @@ static int pmic0_pendet(void *dev_id)
487 338
488 msleep(WAIT_ADC_COMPLETION); 339 msleep(WAIT_ADC_COMPLETION);
489 340
490 /*Read touch screen channels till pen removed 341 return 0;
491 * Freescale reports constant value of z for all points 342
492 * z is high when screen is not touched and low when touched 343ipc_error:
493 * Map high z value to not touched and low z value to pen touched 344 dev_err(&tsdev->spi->dev, "ipc error during %s\n", __func__);
494 */ 345 return err;
495 touched = mrstouch_pmic_fs_adc_read(tsdev); 346}
496 while (touched > TOUCH_PRESSURE) { 347
497 touched = mrstouch_pmic_fs_adc_read(tsdev); 348static int mrstouch_fs_adc_read(struct mrstouch_dev *tsdev,
498 msleep(WAIT_ADC_COMPLETION); 349 u16 *x, u16 *y, u16 *z)
499 } 350{
351 int err;
352 u16 result;
353 u16 reg[4];
354 u8 data[4];
355
356 result = PMIC_REG_ADCSNS0H + tsdev->asr;
357
358 reg[0] = result + 4;
359 reg[1] = result + 5;
360 reg[2] = result + 16;
361 reg[3] = result + 17;
362
363 err = intel_scu_ipc_readv(reg, data, 4);
364 if (err)
365 goto ipc_error;
366
367 *x = data[0] << 3; /* Higher 7 bits */
368 *x |= data[1] & 0x7; /* Lower 3 bits */
369 *x &= 0x3FF;
370
371 *y = data[2] << 3; /* Higher 7 bits */
372 *y |= data[3] & 0x7; /* Lower 3 bits */
373 *y &= 0x3FF;
374
375 /* Read Z value */
376 reg[0] = result + 28;
377 reg[1] = result + 29;
378
379 err = intel_scu_ipc_readv(reg, data, 4);
380 if (err)
381 goto ipc_error;
382
383 *z = data[0] << 3; /* Higher 7 bits */
384 *z |= data[1] & 0x7; /* Lower 3 bits */
385 *z &= 0x3FF;
386
387 return 0;
388
389ipc_error:
390 dev_err(&tsdev->spi->dev, "ipc error during %s\n", __func__);
391 return err;
392}
393
394static int mrstouch_fs_adc_read_finish(struct mrstouch_dev *tsdev)
395{
396 int err, count;
397 u16 chan;
398 u16 reg[5];
399 u8 data[5];
500 400
501 /* Clear all TS channels */ 401 /* Clear all TS channels */
502 chan = PMICADDR0 + tsdev->asr; 402 chan = PMICADDR0 + tsdev->asr;
@@ -520,252 +420,296 @@ static int pmic0_pendet(void *dev_id)
520 if (err) 420 if (err)
521 goto ipc_error; 421 goto ipc_error;
522 422
423 /* Start ADC */
424 err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
425 if (err)
426 goto ipc_error;
427
523 return 0; 428 return 0;
524 429
525ipc_error: 430ipc_error:
526 dev_err(&tsdev->spi->dev, "ipc error during pendet\n"); 431 dev_err(&tsdev->spi->dev, "ipc error during %s\n", __func__);
527 return err; 432 return err;
528} 433}
529 434
530 435static void mrstouch_report_event(struct input_dev *input,
531/* To enable X, Y and Z bias values 436 unsigned int x, unsigned int y, unsigned int z)
532 * Enables YPYM for X channels and XPXM for Y channels
533 */
534static int mrstouch_ts_bias_set(uint offset, uint bias)
535{ 437{
536 int count; 438 if (z > MRST_PRESSURE_NOMINAL) {
537 u16 chan, start; 439 /* Pen touched, report button touch and coordinates */
538 u16 reg[4]; 440 input_report_key(input, BTN_TOUCH, 1);
539 u8 data[4]; 441 input_report_abs(input, ABS_X, x);
540 442 input_report_abs(input, ABS_Y, y);
541 chan = PMICADDR0 + offset; 443 } else {
542 start = MRST_TS_CHAN10; 444 input_report_key(input, BTN_TOUCH, 0);
543
544 for (count = 0; count <= 3; count++) {
545 reg[count] = chan++;
546 data[count] = bias | (start + count);
547 } 445 }
548 return intel_scu_ipc_writev(reg, data, 4); 446
447 input_report_abs(input, ABS_PRESSURE, z);
448 input_sync(input);
549} 449}
550 450
551/* To read touch screen channel values */ 451/* PENDET interrupt handler */
552static int mrstouch_adc_read(struct mrstouch_dev *tsdev) 452static irqreturn_t mrstouch_pendet_irq(int irq, void *dev_id)
553{ 453{
554 int err; 454 struct mrstouch_dev *tsdev = dev_id;
555 u16 xp, xm, yp, ym, zp, zm; 455 u16 x, y, z;
556 456
557 /* configure Y bias for X channels */ 457 /*
558 err = mrstouch_ts_bias_set(tsdev->asr, YBIAS); 458 * Should we lower thread priority? Probably not, since we are
559 if (err) 459 * not spinning but sleeping...
560 goto ipc_error; 460 */
561
562 msleep(WAIT_ADC_COMPLETION);
563 461
564 /* read x+ and x- channels */ 462 if (tsdev->read_prepare(tsdev))
565 err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &xp, &xm); 463 goto out;
566 if (err)
567 goto ipc_error;
568 464
569 /* configure x bias for y channels */ 465 do {
570 err = mrstouch_ts_bias_set(tsdev->asr, XBIAS); 466 if (tsdev->read(tsdev, &x, &y, &z))
571 if (err) 467 break;
572 goto ipc_error;
573 468
574 msleep(WAIT_ADC_COMPLETION); 469 mrstouch_report_event(tsdev->input, x, y, z);
470 } while (z > MRST_PRESSURE_NOMINAL);
575 471
576 /* read y+ and y- channels */ 472 tsdev->read_finish(tsdev);
577 err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, &yp, &ym);
578 if (err)
579 goto ipc_error;
580 473
581 /* configure z bias for x and y channels */ 474out:
582 err = mrstouch_ts_bias_set(tsdev->asr, ZBIAS); 475 return IRQ_HANDLED;
583 if (err) 476}
584 goto ipc_error;
585 477
586 msleep(WAIT_ADC_COMPLETION); 478/* Utility to read PMIC ID */
479static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev)
480{
481 int err;
482 u8 r;
587 483
588 /* read z+ and z- channels */ 484 err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
589 err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &zp, &zm);
590 if (err) 485 if (err)
591 goto ipc_error; 486 return err;
592
593 mrstouch_report_xy(tsdev, xp, yp, zp); /* report x and y to eventX */
594
595 return zp;
596
597ipc_error:
598 dev_err(&tsdev->spi->dev, "ipc error during adc read\n");
599 return err;
600}
601 487
602/* PENDET interrupt handler function for NEC and MAXIM */ 488 *vendor = r & 0x7;
603static void pmic12_pendet(void *data) 489 *rev = (r >> 3) & 0x7;
604{
605 unsigned int touched;
606 struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
607 490
608 /* read touch screen channels till pen removed */ 491 return 0;
609 do {
610 touched = mrstouch_adc_read(tsdev);
611 } while (touched > TOUCH_PRESSURE);
612} 492}
613 493
614/* Handler to process PENDET interrupt */ 494/*
615int mrstouch_pendet(void *data) 495 * Parse ADC channels to find end of the channel configured by other ADC user
496 * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
497 */
498static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev)
616{ 499{
617 struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data; 500 int err, i, j, found;
618 while (1) { 501 u32 r32;
619 /* Wait for PENDET interrupt */
620 if (mutex_lock_interruptible(&tsdev->lock)) {
621 msleep(WAIT_ADC_COMPLETION);
622 continue;
623 }
624 502
625 if (tsdev->busy) 503 found = -1;
626 return 0;
627 504
628 tsdev->busy = true; 505 for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
506 if (found >= 0)
507 break;
629 508
630 if (tsdev->vendor == PMIC_VENDOR_NEC || 509 err = intel_scu_ipc_ioread32(PMICADDR0, &r32);
631 tsdev->vendor == PMIC_VENDOR_MAXIM) { 510 if (err)
632 /* PENDET must be disabled in NEC before reading ADC */ 511 return err;
633 pendet_enable(tsdev,false); /* Disbale PENDET */
634 pmic12_pendet(tsdev);
635 pendet_enable(tsdev, true); /*Enable PENDET */
636 } else if (tsdev->vendor == PMIC_VENDOR_FS) {
637 pendet_umask(); /* Stop ADC */
638 pmic0_pendet(tsdev);
639 pendet_mask(); /* Stop ADC */
640 } else
641 dev_err(&tsdev->spi->dev, "Unsupported touchscreen: %d\n",
642 tsdev->vendor);
643 512
644 tsdev->busy = false; 513 for (j = 0; j < 32; j+= 8) {
514 if (((r32 >> j) & 0xFF) == END_OF_CHANNEL) {
515 found = i;
516 break;
517 }
518 }
519 }
520 if (found < 0)
521 return 0;
645 522
523 if (tsdev->vendor == PMIC_VENDOR_FS) {
524 if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
525 return -ENOSPC;
526 } else {
527 if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
528 return -ENOSPC;
646 } 529 }
647 return 0; 530 return found;
648} 531}
649 532
650/* PENDET interrupt handler */ 533
651static irqreturn_t pendet_intr_handler(int irq, void *handle) 534/*
535 * Writes touch screen channels to ADC address selection registers
536 */
537static int __devinit mrstouch_ts_chan_set(uint offset)
652{ 538{
653 struct mrstouch_dev *tsdev = (struct mrstouch_dev *)handle; 539 int count;
540 u16 chan;
541 u16 reg[5];
542 u8 data[5];
654 543
655 mutex_unlock(&tsdev->lock); 544 chan = PMICADDR0 + offset;
656 return IRQ_HANDLED; 545 for (count = 0; count <= 3; count++) {
546 reg[count] = chan++;
547 data[count] = MRST_TS_CHAN10 + count;
548 }
549 reg[count] = chan;
550 data[count] = END_OF_CHANNEL;
551
552 return intel_scu_ipc_writev(reg, data, 5);
657} 553}
658 554
659/* Intializes input device and registers with input subsystem */ 555/* Initialize ADC */
660static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi) 556static int __devinit mrstouch_adc_init(struct mrstouch_dev *tsdev)
661{ 557{
662 int err = 0; 558 int err, start;
559 u8 ra, rm;
663 560
664 tsdev->input = input_allocate_device(); 561 err = mrstouch_read_pmic_id(&tsdev->vendor, &tsdev->rev);
665 if (!tsdev->input) { 562 if (err) {
666 dev_err(&tsdev->spi->dev, "Unable to allocate input device.\n"); 563 dev_err(&tsdev->spi->dev, "Unable to read PMIC id\n");
667 return -ENOMEM; 564 return err;
668 } 565 }
669 566
670 tsdev->input->name = "mrst_touchscreen"; 567 switch (tsdev->vendor) {
671 snprintf(tsdev->phys, sizeof(tsdev->phys), 568 case PMIC_VENDOR_NEC:
672 "%s/input0", dev_name(&spi->dev)); 569 case PMIC_VENDOR_MAXIM:
673 tsdev->input->phys = tsdev->phys; 570 tsdev->read_prepare = mrstouch_nec_adc_read_prepare;
674 tsdev->input->dev.parent = &spi->dev; 571 tsdev->read = mrstouch_nec_adc_read;
572 tsdev->read_finish = mrstouch_nec_adc_read_finish;
573 break;
574
575 case PMIC_VENDOR_FS:
576 tsdev->read_prepare = mrstouch_fs_adc_read_prepare;
577 tsdev->read = mrstouch_fs_adc_read;
578 tsdev->read_finish = mrstouch_fs_adc_read_finish;
579 break;
580
581 default:
582 dev_err(&tsdev->spi->dev,
583 "Unsupported touchscreen: %d\n", tsdev->vendor);
584 return -ENXIO;
585 }
675 586
676 tsdev->input->id.vendor = tsdev->vendor; 587 start = mrstouch_chan_parse(tsdev);
677 tsdev->input->id.version = tsdev->rev; 588 if (start < 0) {
589 dev_err(&tsdev->spi->dev, "Unable to parse channels\n");
590 return start;
591 }
678 592
679 tsdev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 593 tsdev->asr = start;
680 tsdev->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
681 594
682 input_set_abs_params(tsdev->input, ABS_X, MIN_X, MAX_X, 0, 0); 595 /*
683 input_set_abs_params(tsdev->input, ABS_Y, MIN_Y, MAX_Y, 0, 0); 596 * ADC power on, start, enable PENDET and set loop delay
684 input_set_abs_params(tsdev->input, ABS_PRESSURE, MIN_P, MAX_P, 0, 0); 597 * ADC loop delay is set to 4.5 ms approximately
598 * Loop delay more than this results in jitter in adc readings
599 * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
600 * interrupt generation sometimes.
601 */
685 602
686 err = input_register_device(tsdev->input); 603 if (tsdev->vendor == PMIC_VENDOR_FS) {
687 if (err) { 604 ra = 0xE0 | ADC_LOOP_DELAY0;
688 dev_err(&tsdev->spi->dev, "unable to register input device\n"); 605 rm = 0x5;
689 input_free_device(tsdev->input); 606 } else {
690 return err; 607 /* NEC and MAXIm not consistent with loop delay 0 */
608 ra = 0xE0 | ADC_LOOP_DELAY1;
609 rm = 0x0;
610
611 /* configure touch screen channels */
612 err = mrstouch_ts_chan_set(tsdev->asr);
613 if (err)
614 return err;
691 } 615 }
692 return 0;
693 616
617 err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
618 if (err)
619 return err;
620
621 err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
622 if (err)
623 return err;
624
625 return 0;
694} 626}
695 627
628
696/* Probe function for touch screen driver */ 629/* Probe function for touch screen driver */
697static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi) 630static int __devinit mrstouch_probe(struct spi_device *spi)
698{ 631{
699 int err;
700 unsigned int myirq;
701 struct mrstouch_dev *tsdev; 632 struct mrstouch_dev *tsdev;
633 struct input_dev *input;
634 int err;
702 635
703 mrstouchdevp = NULL; 636 if (!spi->irq) {
704 myirq = mrstouch_spi->irq; 637 dev_err(&spi->dev, "no interrupt assigned\n");
705
706 if (!mrstouch_spi->irq) {
707 dev_err(&mrstouch_spi->dev, "no interrupt assigned\n");
708 return -EINVAL; 638 return -EINVAL;
709 } 639 }
710 640
711 tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL); 641 tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
712 if (!tsdev) { 642 input = input_allocate_device();
713 dev_err(&mrstouch_spi->dev, "unable to allocate memory\n"); 643 if (!tsdev || !input) {
714 return -ENOMEM; 644 dev_err(&spi->dev, "unable to allocate memory\n");
645 err = -ENOMEM;
646 goto err_free_mem;
715 } 647 }
716 648
717 tsdev->irq = myirq; 649 tsdev->spi = spi;
718 mrstouchdevp = tsdev; 650 tsdev->input = input;
651 tsdev->irq = spi->irq;
652
653 snprintf(tsdev->phys, sizeof(tsdev->phys),
654 "%s/input0", dev_name(&spi->dev));
719 655
720 err = mrstouch_adc_init(tsdev); 656 err = mrstouch_adc_init(tsdev);
721 if (err) { 657 if (err) {
722 dev_err(&mrstouch_spi->dev, "ADC init failed\n"); 658 dev_err(&spi->dev, "ADC initialization failed\n");
723 goto mrstouch_err_free_mem; 659 goto err_free_mem;
724 } 660 }
725 661
726 dev_set_drvdata(&mrstouch_spi->dev, tsdev); 662 input->name = "mrst_touchscreen";
727 tsdev->spi = mrstouch_spi; 663 input->phys = tsdev->phys;
664 input->dev.parent = &spi->dev;
728 665
729 err = ts_input_dev_init(tsdev, mrstouch_spi); 666 input->id.vendor = tsdev->vendor;
730 if (err) { 667 input->id.version = tsdev->rev;
731 dev_err(&tsdev->spi->dev, "ts_input_dev_init failed");
732 goto mrstouch_err_free_dev;
733 }
734 668
735 mutex_init(&tsdev->lock); 669 input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
736 mutex_lock(&tsdev->lock); 670 input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
737 671
738 err = request_irq(myirq, pendet_intr_handler, 672 input_set_abs_params(tsdev->input, ABS_X,
739 0, "mrstouch", tsdev); 673 MRST_X_MIN, MRST_X_MAX, MRST_X_FUZZ, 0);
674 input_set_abs_params(tsdev->input, ABS_Y,
675 MRST_Y_MIN, MRST_Y_MAX, MRST_Y_FUZZ, 0);
676 input_set_abs_params(tsdev->input, ABS_PRESSURE,
677 MRST_PRESSURE_MIN, MRST_PRESSURE_MAX, 0, 0);
678
679 err = request_threaded_irq(tsdev->irq, NULL, mrstouch_pendet_irq,
680 0, "mrstouch", tsdev);
740 if (err) { 681 if (err) {
741 dev_err(&tsdev->spi->dev, "unable to allocate irq\n"); 682 dev_err(&tsdev->spi->dev, "unable to allocate irq\n");
742 goto mrstouch_err_free_dev; 683 goto err_free_mem;
743 } 684 }
744 685
745 tsdev->pendet_thrd = kthread_run(mrstouch_pendet, 686 err = input_register_device(tsdev->input);
746 (void *)tsdev, "pendet handler"); 687 if (err) {
747 if (IS_ERR(tsdev->pendet_thrd)) { 688 dev_err(&tsdev->spi->dev, "unable to register input device\n");
748 dev_err(&tsdev->spi->dev, "kthread_run failed\n"); 689 goto err_free_irq;
749 err = PTR_ERR(tsdev->pendet_thrd);
750 goto mrstouch_err_free_irq;
751 } 690 }
691
692 spi_set_drvdata(spi, tsdev);
752 return 0; 693 return 0;
753mrstouch_err_free_irq: 694
754 free_irq(myirq, tsdev); 695err_free_irq:
755mrstouch_err_free_dev: 696 free_irq(tsdev->irq, tsdev);
756 input_unregister_device(tsdev->input); 697err_free_mem:
757mrstouch_err_free_mem: 698 input_free_device(input);
758 kfree(tsdev); 699 kfree(tsdev);
759 return err; 700 return err;
760} 701}
761 702
762static int mrstouch_remove(struct spi_device *spi) 703static int __devexit mrstouch_remove(struct spi_device *spi)
763{ 704{
764 free_irq(mrstouchdevp->irq, mrstouchdevp); 705 struct mrstouch_dev *tsdev = spi_get_drvdata(spi);
765 if (mrstouchdevp->pendet_thrd) 706
766 kthread_stop(mrstouchdevp->pendet_thrd); 707 free_irq(tsdev->irq, tsdev);
767 input_unregister_device(mrstouchdevp->input); 708 input_unregister_device(tsdev->input);
768 kfree(mrstouchdevp); 709 kfree(tsdev);
710
711 spi_set_drvdata(spi, NULL);
712
769 return 0; 713 return 0;
770} 714}
771 715
@@ -776,30 +720,20 @@ static struct spi_driver mrstouch_driver = {
776 .owner = THIS_MODULE, 720 .owner = THIS_MODULE,
777 }, 721 },
778 .probe = mrstouch_probe, 722 .probe = mrstouch_probe,
779 .remove = mrstouch_remove, 723 .remove = __devexit_p(mrstouch_remove),
780}; 724};
781 725
782static int __init mrstouch_module_init(void) 726static int __init mrstouch_init(void)
783{ 727{
784 int err; 728 return spi_register_driver(&mrstouch_driver);
785
786 err = spi_register_driver(&mrstouch_driver);
787 if (err) {
788 printk(KERN_ERR "%s(%d)", "SPI PENDET failed", err);
789 return err;;
790 }
791
792 return 0;
793} 729}
730module_init(mrstouch_init);
794 731
795static void __exit mrstouch_module_exit(void) 732static void __exit mrstouch_exit(void)
796{ 733{
797 spi_unregister_driver(&mrstouch_driver); 734 spi_unregister_driver(&mrstouch_driver);
798 return;
799} 735}
800 736module_exit(mrstouch_exit);
801module_init(mrstouch_module_init);
802module_exit(mrstouch_module_exit);
803 737
804MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com"); 738MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
805MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver"); 739MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");