diff options
author | Dmitry Torokhov <dtor@mail.ru> | 2010-09-01 01:57:28 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-09-01 22:43:08 -0400 |
commit | 95b7127c1141bddd3cff30415c7d6e656f335a35 (patch) | |
tree | e715bc6002139fd021fb14fdff5e0f9d5ac26b70 | |
parent | aff4c343614f0c9980352810df70969821cba95f (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.c | 892 |
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 6fed01ee82da..be7ba7b47591 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 */ |
108 | struct mrstouch_dev { | 96 | struct 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 */ | ||
126 | static struct mrstouch_dev *mrstouchdevp; | ||
127 | 109 | ||
128 | /* Utility to read PMIC ID */ | 110 | |
129 | static int mrstouch_pmic_id(uint *vendor, uint *rev) | 111 | /*************************** NEC and Maxim Interface ************************/ |
112 | |||
113 | static 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, ®); |
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 | */ |
148 | static int mrstouch_chan_parse(struct mrstouch_dev *tsdev) | 131 | static 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 | */ | ||
188 | static 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 | */ |
242 | static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm) | 187 | static 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 | */ |
275 | static int mrstouch_ts_chan_set(uint offset) | 221 | static 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 */ | ||
294 | static 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 */ | ||
340 | static 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 */ | ||
385 | static 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 */ | ||
391 | static 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 */ |
397 | static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev) | 240 | static 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 | ||
438 | ipc_error: | 284 | ipc_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 | |
444 | static int pmic0_pendet(void *dev_id) | 290 | /*************************** Freescale Interface ************************/ |
291 | |||
292 | static 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 | 343 | ipc_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); | 348 | static 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 | |||
389 | ipc_error: | ||
390 | dev_err(&tsdev->spi->dev, "ipc error during %s\n", __func__); | ||
391 | return err; | ||
392 | } | ||
393 | |||
394 | static 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 | ||
525 | ipc_error: | 430 | ipc_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 | 435 | static 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 | */ | ||
534 | static 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 */ |
552 | static int mrstouch_adc_read(struct mrstouch_dev *tsdev) | 452 | static 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 */ | 474 | out: |
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 */ |
479 | static 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 | |||
597 | ipc_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; |
603 | static 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 | /* |
615 | int 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 | */ | ||
498 | static 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 | |
651 | static irqreturn_t pendet_intr_handler(int irq, void *handle) | 534 | /* |
535 | * Writes touch screen channels to ADC address selection registers | ||
536 | */ | ||
537 | static 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 */ |
660 | static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi) | 556 | static 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 */ |
697 | static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi) | 630 | static 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; |
753 | mrstouch_err_free_irq: | 694 | |
754 | free_irq(myirq, tsdev); | 695 | err_free_irq: |
755 | mrstouch_err_free_dev: | 696 | free_irq(tsdev->irq, tsdev); |
756 | input_unregister_device(tsdev->input); | 697 | err_free_mem: |
757 | mrstouch_err_free_mem: | 698 | input_free_device(input); |
758 | kfree(tsdev); | 699 | kfree(tsdev); |
759 | return err; | 700 | return err; |
760 | } | 701 | } |
761 | 702 | ||
762 | static int mrstouch_remove(struct spi_device *spi) | 703 | static 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 | ||
782 | static int __init mrstouch_module_init(void) | 726 | static 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 | } |
730 | module_init(mrstouch_init); | ||
794 | 731 | ||
795 | static void __exit mrstouch_module_exit(void) | 732 | static void __exit mrstouch_exit(void) |
796 | { | 733 | { |
797 | spi_unregister_driver(&mrstouch_driver); | 734 | spi_unregister_driver(&mrstouch_driver); |
798 | return; | ||
799 | } | 735 | } |
800 | 736 | module_exit(mrstouch_exit); | |
801 | module_init(mrstouch_module_init); | ||
802 | module_exit(mrstouch_module_exit); | ||
803 | 737 | ||
804 | MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com"); | 738 | MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com"); |
805 | MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver"); | 739 | MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver"); |