diff options
Diffstat (limited to 'drivers/input/misc/ad714x.c')
-rw-r--r-- | drivers/input/misc/ad714x.c | 1331 |
1 files changed, 1331 insertions, 0 deletions
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c new file mode 100644 index 000000000000..691b1d37331f --- /dev/null +++ b/drivers/input/misc/ad714x.c | |||
@@ -0,0 +1,1331 @@ | |||
1 | /* | ||
2 | * AD714X CapTouch Programmable Controller driver | ||
3 | * | ||
4 | * Copyright 2009 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2 or later. | ||
7 | */ | ||
8 | |||
9 | #include <linux/device.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/input.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/input/ad714x.h> | ||
15 | #include "ad714x.h" | ||
16 | |||
17 | #define AD714X_PWR_CTRL 0x0 | ||
18 | #define AD714X_STG_CAL_EN_REG 0x1 | ||
19 | #define AD714X_AMB_COMP_CTRL0_REG 0x2 | ||
20 | #define AD714X_PARTID_REG 0x17 | ||
21 | #define AD7147_PARTID 0x1470 | ||
22 | #define AD7142_PARTID 0xE620 | ||
23 | #define AD714X_STAGECFG_REG 0x80 | ||
24 | #define AD714X_SYSCFG_REG 0x0 | ||
25 | |||
26 | #define STG_LOW_INT_EN_REG 0x5 | ||
27 | #define STG_HIGH_INT_EN_REG 0x6 | ||
28 | #define STG_COM_INT_EN_REG 0x7 | ||
29 | #define STG_LOW_INT_STA_REG 0x8 | ||
30 | #define STG_HIGH_INT_STA_REG 0x9 | ||
31 | #define STG_COM_INT_STA_REG 0xA | ||
32 | |||
33 | #define CDC_RESULT_S0 0xB | ||
34 | #define CDC_RESULT_S1 0xC | ||
35 | #define CDC_RESULT_S2 0xD | ||
36 | #define CDC_RESULT_S3 0xE | ||
37 | #define CDC_RESULT_S4 0xF | ||
38 | #define CDC_RESULT_S5 0x10 | ||
39 | #define CDC_RESULT_S6 0x11 | ||
40 | #define CDC_RESULT_S7 0x12 | ||
41 | #define CDC_RESULT_S8 0x13 | ||
42 | #define CDC_RESULT_S9 0x14 | ||
43 | #define CDC_RESULT_S10 0x15 | ||
44 | #define CDC_RESULT_S11 0x16 | ||
45 | |||
46 | #define STAGE0_AMBIENT 0xF1 | ||
47 | #define STAGE1_AMBIENT 0x115 | ||
48 | #define STAGE2_AMBIENT 0x139 | ||
49 | #define STAGE3_AMBIENT 0x15D | ||
50 | #define STAGE4_AMBIENT 0x181 | ||
51 | #define STAGE5_AMBIENT 0x1A5 | ||
52 | #define STAGE6_AMBIENT 0x1C9 | ||
53 | #define STAGE7_AMBIENT 0x1ED | ||
54 | #define STAGE8_AMBIENT 0x211 | ||
55 | #define STAGE9_AMBIENT 0x234 | ||
56 | #define STAGE10_AMBIENT 0x259 | ||
57 | #define STAGE11_AMBIENT 0x27D | ||
58 | |||
59 | #define PER_STAGE_REG_NUM 36 | ||
60 | #define STAGE_NUM 12 | ||
61 | #define STAGE_CFGREG_NUM 8 | ||
62 | #define SYS_CFGREG_NUM 8 | ||
63 | |||
64 | /* | ||
65 | * driver information which will be used to maintain the software flow | ||
66 | */ | ||
67 | enum ad714x_device_state { IDLE, JITTER, ACTIVE, SPACE }; | ||
68 | |||
69 | struct ad714x_slider_drv { | ||
70 | int highest_stage; | ||
71 | int abs_pos; | ||
72 | int flt_pos; | ||
73 | enum ad714x_device_state state; | ||
74 | struct input_dev *input; | ||
75 | }; | ||
76 | |||
77 | struct ad714x_wheel_drv { | ||
78 | int abs_pos; | ||
79 | int flt_pos; | ||
80 | int pre_mean_value; | ||
81 | int pre_highest_stage; | ||
82 | int pre_mean_value_no_offset; | ||
83 | int mean_value; | ||
84 | int mean_value_no_offset; | ||
85 | int pos_offset; | ||
86 | int pos_ratio; | ||
87 | int highest_stage; | ||
88 | enum ad714x_device_state state; | ||
89 | struct input_dev *input; | ||
90 | }; | ||
91 | |||
92 | struct ad714x_touchpad_drv { | ||
93 | int x_highest_stage; | ||
94 | int x_flt_pos; | ||
95 | int x_abs_pos; | ||
96 | int y_highest_stage; | ||
97 | int y_flt_pos; | ||
98 | int y_abs_pos; | ||
99 | int left_ep; | ||
100 | int left_ep_val; | ||
101 | int right_ep; | ||
102 | int right_ep_val; | ||
103 | int top_ep; | ||
104 | int top_ep_val; | ||
105 | int bottom_ep; | ||
106 | int bottom_ep_val; | ||
107 | enum ad714x_device_state state; | ||
108 | struct input_dev *input; | ||
109 | }; | ||
110 | |||
111 | struct ad714x_button_drv { | ||
112 | enum ad714x_device_state state; | ||
113 | /* | ||
114 | * Unlike slider/wheel/touchpad, all buttons point to | ||
115 | * same input_dev instance | ||
116 | */ | ||
117 | struct input_dev *input; | ||
118 | }; | ||
119 | |||
120 | struct ad714x_driver_data { | ||
121 | struct ad714x_slider_drv *slider; | ||
122 | struct ad714x_wheel_drv *wheel; | ||
123 | struct ad714x_touchpad_drv *touchpad; | ||
124 | struct ad714x_button_drv *button; | ||
125 | }; | ||
126 | |||
127 | /* | ||
128 | * information to integrate all things which will be private data | ||
129 | * of spi/i2c device | ||
130 | */ | ||
131 | struct ad714x_chip { | ||
132 | unsigned short h_state; | ||
133 | unsigned short l_state; | ||
134 | unsigned short c_state; | ||
135 | unsigned short adc_reg[STAGE_NUM]; | ||
136 | unsigned short amb_reg[STAGE_NUM]; | ||
137 | unsigned short sensor_val[STAGE_NUM]; | ||
138 | |||
139 | struct ad714x_platform_data *hw; | ||
140 | struct ad714x_driver_data *sw; | ||
141 | |||
142 | int irq; | ||
143 | struct device *dev; | ||
144 | ad714x_read_t read; | ||
145 | ad714x_write_t write; | ||
146 | |||
147 | struct mutex mutex; | ||
148 | |||
149 | unsigned product; | ||
150 | unsigned version; | ||
151 | }; | ||
152 | |||
153 | static void ad714x_use_com_int(struct ad714x_chip *ad714x, | ||
154 | int start_stage, int end_stage) | ||
155 | { | ||
156 | unsigned short data; | ||
157 | unsigned short mask; | ||
158 | |||
159 | mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage); | ||
160 | |||
161 | ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data); | ||
162 | data |= 1 << start_stage; | ||
163 | ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data); | ||
164 | |||
165 | ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data); | ||
166 | data &= ~mask; | ||
167 | ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data); | ||
168 | } | ||
169 | |||
170 | static void ad714x_use_thr_int(struct ad714x_chip *ad714x, | ||
171 | int start_stage, int end_stage) | ||
172 | { | ||
173 | unsigned short data; | ||
174 | unsigned short mask; | ||
175 | |||
176 | mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage); | ||
177 | |||
178 | ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data); | ||
179 | data &= ~(1 << start_stage); | ||
180 | ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data); | ||
181 | |||
182 | ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data); | ||
183 | data |= mask; | ||
184 | ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data); | ||
185 | } | ||
186 | |||
187 | static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x, | ||
188 | int start_stage, int end_stage) | ||
189 | { | ||
190 | int max_res = 0; | ||
191 | int max_idx = 0; | ||
192 | int i; | ||
193 | |||
194 | for (i = start_stage; i <= end_stage; i++) { | ||
195 | if (ad714x->sensor_val[i] > max_res) { | ||
196 | max_res = ad714x->sensor_val[i]; | ||
197 | max_idx = i; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | return max_idx; | ||
202 | } | ||
203 | |||
204 | static int ad714x_cal_abs_pos(struct ad714x_chip *ad714x, | ||
205 | int start_stage, int end_stage, | ||
206 | int highest_stage, int max_coord) | ||
207 | { | ||
208 | int a_param, b_param; | ||
209 | |||
210 | if (highest_stage == start_stage) { | ||
211 | a_param = ad714x->sensor_val[start_stage + 1]; | ||
212 | b_param = ad714x->sensor_val[start_stage] + | ||
213 | ad714x->sensor_val[start_stage + 1]; | ||
214 | } else if (highest_stage == end_stage) { | ||
215 | a_param = ad714x->sensor_val[end_stage] * | ||
216 | (end_stage - start_stage) + | ||
217 | ad714x->sensor_val[end_stage - 1] * | ||
218 | (end_stage - start_stage - 1); | ||
219 | b_param = ad714x->sensor_val[end_stage] + | ||
220 | ad714x->sensor_val[end_stage - 1]; | ||
221 | } else { | ||
222 | a_param = ad714x->sensor_val[highest_stage] * | ||
223 | (highest_stage - start_stage) + | ||
224 | ad714x->sensor_val[highest_stage - 1] * | ||
225 | (highest_stage - start_stage - 1) + | ||
226 | ad714x->sensor_val[highest_stage + 1] * | ||
227 | (highest_stage - start_stage + 1); | ||
228 | b_param = ad714x->sensor_val[highest_stage] + | ||
229 | ad714x->sensor_val[highest_stage - 1] + | ||
230 | ad714x->sensor_val[highest_stage + 1]; | ||
231 | } | ||
232 | |||
233 | return (max_coord / (end_stage - start_stage)) * a_param / b_param; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * One button can connect to multi positive and negative of CDCs | ||
238 | * Multi-buttons can connect to same positive/negative of one CDC | ||
239 | */ | ||
240 | static void ad714x_button_state_machine(struct ad714x_chip *ad714x, int idx) | ||
241 | { | ||
242 | struct ad714x_button_plat *hw = &ad714x->hw->button[idx]; | ||
243 | struct ad714x_button_drv *sw = &ad714x->sw->button[idx]; | ||
244 | |||
245 | switch (sw->state) { | ||
246 | case IDLE: | ||
247 | if (((ad714x->h_state & hw->h_mask) == hw->h_mask) && | ||
248 | ((ad714x->l_state & hw->l_mask) == hw->l_mask)) { | ||
249 | dev_dbg(ad714x->dev, "button %d touched\n", idx); | ||
250 | input_report_key(sw->input, hw->keycode, 1); | ||
251 | input_sync(sw->input); | ||
252 | sw->state = ACTIVE; | ||
253 | } | ||
254 | break; | ||
255 | |||
256 | case ACTIVE: | ||
257 | if (((ad714x->h_state & hw->h_mask) != hw->h_mask) || | ||
258 | ((ad714x->l_state & hw->l_mask) != hw->l_mask)) { | ||
259 | dev_dbg(ad714x->dev, "button %d released\n", idx); | ||
260 | input_report_key(sw->input, hw->keycode, 0); | ||
261 | input_sync(sw->input); | ||
262 | sw->state = IDLE; | ||
263 | } | ||
264 | break; | ||
265 | |||
266 | default: | ||
267 | break; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * The response of a sensor is defined by the absolute number of codes | ||
273 | * between the current CDC value and the ambient value. | ||
274 | */ | ||
275 | static void ad714x_slider_cal_sensor_val(struct ad714x_chip *ad714x, int idx) | ||
276 | { | ||
277 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
278 | int i; | ||
279 | |||
280 | for (i = hw->start_stage; i <= hw->end_stage; i++) { | ||
281 | ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, | ||
282 | &ad714x->adc_reg[i]); | ||
283 | ad714x->read(ad714x->dev, | ||
284 | STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, | ||
285 | &ad714x->amb_reg[i]); | ||
286 | |||
287 | ad714x->sensor_val[i] = abs(ad714x->adc_reg[i] - | ||
288 | ad714x->amb_reg[i]); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | static void ad714x_slider_cal_highest_stage(struct ad714x_chip *ad714x, int idx) | ||
293 | { | ||
294 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
295 | struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; | ||
296 | |||
297 | sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage, | ||
298 | hw->end_stage); | ||
299 | |||
300 | dev_dbg(ad714x->dev, "slider %d highest_stage:%d\n", idx, | ||
301 | sw->highest_stage); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * The formulae are very straight forward. It uses the sensor with the | ||
306 | * highest response and the 2 adjacent ones. | ||
307 | * When Sensor 0 has the highest response, only sensor 0 and sensor 1 | ||
308 | * are used in the calculations. Similarly when the last sensor has the | ||
309 | * highest response, only the last sensor and the second last sensors | ||
310 | * are used in the calculations. | ||
311 | * | ||
312 | * For i= idx_of_peak_Sensor-1 to i= idx_of_peak_Sensor+1 | ||
313 | * v += Sensor response(i)*i | ||
314 | * w += Sensor response(i) | ||
315 | * POS=(Number_of_Positions_Wanted/(Number_of_Sensors_Used-1)) *(v/w) | ||
316 | */ | ||
317 | static void ad714x_slider_cal_abs_pos(struct ad714x_chip *ad714x, int idx) | ||
318 | { | ||
319 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
320 | struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; | ||
321 | |||
322 | sw->abs_pos = ad714x_cal_abs_pos(ad714x, hw->start_stage, hw->end_stage, | ||
323 | sw->highest_stage, hw->max_coord); | ||
324 | |||
325 | dev_dbg(ad714x->dev, "slider %d absolute position:%d\n", idx, | ||
326 | sw->abs_pos); | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * To minimise the Impact of the noise on the algorithm, ADI developed a | ||
331 | * routine that filters the CDC results after they have been read by the | ||
332 | * host processor. | ||
333 | * The filter used is an Infinite Input Response(IIR) filter implemented | ||
334 | * in firmware and attenuates the noise on the CDC results after they've | ||
335 | * been read by the host processor. | ||
336 | * Filtered_CDC_result = (Filtered_CDC_result * (10 - Coefficient) + | ||
337 | * Latest_CDC_result * Coefficient)/10 | ||
338 | */ | ||
339 | static void ad714x_slider_cal_flt_pos(struct ad714x_chip *ad714x, int idx) | ||
340 | { | ||
341 | struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; | ||
342 | |||
343 | sw->flt_pos = (sw->flt_pos * (10 - 4) + | ||
344 | sw->abs_pos * 4)/10; | ||
345 | |||
346 | dev_dbg(ad714x->dev, "slider %d filter position:%d\n", idx, | ||
347 | sw->flt_pos); | ||
348 | } | ||
349 | |||
350 | static void ad714x_slider_use_com_int(struct ad714x_chip *ad714x, int idx) | ||
351 | { | ||
352 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
353 | |||
354 | ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage); | ||
355 | } | ||
356 | |||
357 | static void ad714x_slider_use_thr_int(struct ad714x_chip *ad714x, int idx) | ||
358 | { | ||
359 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
360 | |||
361 | ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage); | ||
362 | } | ||
363 | |||
364 | static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx) | ||
365 | { | ||
366 | struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx]; | ||
367 | struct ad714x_slider_drv *sw = &ad714x->sw->slider[idx]; | ||
368 | unsigned short h_state, c_state; | ||
369 | unsigned short mask; | ||
370 | |||
371 | mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1); | ||
372 | |||
373 | h_state = ad714x->h_state & mask; | ||
374 | c_state = ad714x->c_state & mask; | ||
375 | |||
376 | switch (sw->state) { | ||
377 | case IDLE: | ||
378 | if (h_state) { | ||
379 | sw->state = JITTER; | ||
380 | /* In End of Conversion interrupt mode, the AD714X | ||
381 | * continuously generates hardware interrupts. | ||
382 | */ | ||
383 | ad714x_slider_use_com_int(ad714x, idx); | ||
384 | dev_dbg(ad714x->dev, "slider %d touched\n", idx); | ||
385 | } | ||
386 | break; | ||
387 | |||
388 | case JITTER: | ||
389 | if (c_state == mask) { | ||
390 | ad714x_slider_cal_sensor_val(ad714x, idx); | ||
391 | ad714x_slider_cal_highest_stage(ad714x, idx); | ||
392 | ad714x_slider_cal_abs_pos(ad714x, idx); | ||
393 | sw->flt_pos = sw->abs_pos; | ||
394 | sw->state = ACTIVE; | ||
395 | } | ||
396 | break; | ||
397 | |||
398 | case ACTIVE: | ||
399 | if (c_state == mask) { | ||
400 | if (h_state) { | ||
401 | ad714x_slider_cal_sensor_val(ad714x, idx); | ||
402 | ad714x_slider_cal_highest_stage(ad714x, idx); | ||
403 | ad714x_slider_cal_abs_pos(ad714x, idx); | ||
404 | ad714x_slider_cal_flt_pos(ad714x, idx); | ||
405 | |||
406 | input_report_abs(sw->input, ABS_X, sw->flt_pos); | ||
407 | input_report_key(sw->input, BTN_TOUCH, 1); | ||
408 | } else { | ||
409 | /* When the user lifts off the sensor, configure | ||
410 | * the AD714X back to threshold interrupt mode. | ||
411 | */ | ||
412 | ad714x_slider_use_thr_int(ad714x, idx); | ||
413 | sw->state = IDLE; | ||
414 | input_report_key(sw->input, BTN_TOUCH, 0); | ||
415 | dev_dbg(ad714x->dev, "slider %d released\n", | ||
416 | idx); | ||
417 | } | ||
418 | input_sync(sw->input); | ||
419 | } | ||
420 | break; | ||
421 | |||
422 | default: | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | /* | ||
428 | * When the scroll wheel is activated, we compute the absolute position based | ||
429 | * on the sensor values. To calculate the position, we first determine the | ||
430 | * sensor that has the greatest response among the 8 sensors that constitutes | ||
431 | * the scrollwheel. Then we determined the 2 sensors on either sides of the | ||
432 | * sensor with the highest response and we apply weights to these sensors. | ||
433 | */ | ||
434 | static void ad714x_wheel_cal_highest_stage(struct ad714x_chip *ad714x, int idx) | ||
435 | { | ||
436 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
437 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | ||
438 | |||
439 | sw->pre_highest_stage = sw->highest_stage; | ||
440 | sw->highest_stage = ad714x_cal_highest_stage(ad714x, hw->start_stage, | ||
441 | hw->end_stage); | ||
442 | |||
443 | dev_dbg(ad714x->dev, "wheel %d highest_stage:%d\n", idx, | ||
444 | sw->highest_stage); | ||
445 | } | ||
446 | |||
447 | static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx) | ||
448 | { | ||
449 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
450 | int i; | ||
451 | |||
452 | for (i = hw->start_stage; i <= hw->end_stage; i++) { | ||
453 | ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, | ||
454 | &ad714x->adc_reg[i]); | ||
455 | ad714x->read(ad714x->dev, | ||
456 | STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, | ||
457 | &ad714x->amb_reg[i]); | ||
458 | if (ad714x->adc_reg[i] > ad714x->amb_reg[i]) | ||
459 | ad714x->sensor_val[i] = ad714x->adc_reg[i] - | ||
460 | ad714x->amb_reg[i]; | ||
461 | else | ||
462 | ad714x->sensor_val[i] = 0; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | /* | ||
467 | * When the scroll wheel is activated, we compute the absolute position based | ||
468 | * on the sensor values. To calculate the position, we first determine the | ||
469 | * sensor that has the greatest response among the 8 sensors that constitutes | ||
470 | * the scrollwheel. Then we determined the 2 sensors on either sides of the | ||
471 | * sensor with the highest response and we apply weights to these sensors. The | ||
472 | * result of this computation gives us the mean value which defined by the | ||
473 | * following formula: | ||
474 | * For i= second_before_highest_stage to i= second_after_highest_stage | ||
475 | * v += Sensor response(i)*WEIGHT*(i+3) | ||
476 | * w += Sensor response(i) | ||
477 | * Mean_Value=v/w | ||
478 | * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio | ||
479 | */ | ||
480 | |||
481 | #define WEIGHT_FACTOR 30 | ||
482 | /* This constant prevents the "PositionOffset" from reaching a big value */ | ||
483 | #define OFFSET_POSITION_CLAMP 120 | ||
484 | static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx) | ||
485 | { | ||
486 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
487 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | ||
488 | int stage_num = hw->end_stage - hw->start_stage + 1; | ||
489 | int second_before, first_before, highest, first_after, second_after; | ||
490 | int a_param, b_param; | ||
491 | |||
492 | /* Calculate Mean value */ | ||
493 | |||
494 | second_before = (sw->highest_stage + stage_num - 2) % stage_num; | ||
495 | first_before = (sw->highest_stage + stage_num - 1) % stage_num; | ||
496 | highest = sw->highest_stage; | ||
497 | first_after = (sw->highest_stage + stage_num + 1) % stage_num; | ||
498 | second_after = (sw->highest_stage + stage_num + 2) % stage_num; | ||
499 | |||
500 | if (((sw->highest_stage - hw->start_stage) > 1) && | ||
501 | ((hw->end_stage - sw->highest_stage) > 1)) { | ||
502 | a_param = ad714x->sensor_val[second_before] * | ||
503 | (second_before - hw->start_stage + 3) + | ||
504 | ad714x->sensor_val[first_before] * | ||
505 | (second_before - hw->start_stage + 3) + | ||
506 | ad714x->sensor_val[highest] * | ||
507 | (second_before - hw->start_stage + 3) + | ||
508 | ad714x->sensor_val[first_after] * | ||
509 | (first_after - hw->start_stage + 3) + | ||
510 | ad714x->sensor_val[second_after] * | ||
511 | (second_after - hw->start_stage + 3); | ||
512 | } else { | ||
513 | a_param = ad714x->sensor_val[second_before] * | ||
514 | (second_before - hw->start_stage + 1) + | ||
515 | ad714x->sensor_val[first_before] * | ||
516 | (second_before - hw->start_stage + 2) + | ||
517 | ad714x->sensor_val[highest] * | ||
518 | (second_before - hw->start_stage + 3) + | ||
519 | ad714x->sensor_val[first_after] * | ||
520 | (first_after - hw->start_stage + 4) + | ||
521 | ad714x->sensor_val[second_after] * | ||
522 | (second_after - hw->start_stage + 5); | ||
523 | } | ||
524 | a_param *= WEIGHT_FACTOR; | ||
525 | |||
526 | b_param = ad714x->sensor_val[second_before] + | ||
527 | ad714x->sensor_val[first_before] + | ||
528 | ad714x->sensor_val[highest] + | ||
529 | ad714x->sensor_val[first_after] + | ||
530 | ad714x->sensor_val[second_after]; | ||
531 | |||
532 | sw->pre_mean_value = sw->mean_value; | ||
533 | sw->mean_value = a_param / b_param; | ||
534 | |||
535 | /* Calculate the offset */ | ||
536 | |||
537 | if ((sw->pre_highest_stage == hw->end_stage) && | ||
538 | (sw->highest_stage == hw->start_stage)) | ||
539 | sw->pos_offset = sw->mean_value; | ||
540 | else if ((sw->pre_highest_stage == hw->start_stage) && | ||
541 | (sw->highest_stage == hw->end_stage)) | ||
542 | sw->pos_offset = sw->pre_mean_value; | ||
543 | |||
544 | if (sw->pos_offset > OFFSET_POSITION_CLAMP) | ||
545 | sw->pos_offset = OFFSET_POSITION_CLAMP; | ||
546 | |||
547 | /* Calculate the mean value without the offset */ | ||
548 | |||
549 | sw->pre_mean_value_no_offset = sw->mean_value_no_offset; | ||
550 | sw->mean_value_no_offset = sw->mean_value - sw->pos_offset; | ||
551 | if (sw->mean_value_no_offset < 0) | ||
552 | sw->mean_value_no_offset = 0; | ||
553 | |||
554 | /* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */ | ||
555 | |||
556 | if ((sw->pre_highest_stage == hw->end_stage) && | ||
557 | (sw->highest_stage == hw->start_stage)) | ||
558 | sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) / | ||
559 | hw->max_coord; | ||
560 | else if ((sw->pre_highest_stage == hw->start_stage) && | ||
561 | (sw->highest_stage == hw->end_stage)) | ||
562 | sw->pos_ratio = (sw->mean_value_no_offset * 100) / | ||
563 | hw->max_coord; | ||
564 | sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio; | ||
565 | if (sw->abs_pos > hw->max_coord) | ||
566 | sw->abs_pos = hw->max_coord; | ||
567 | } | ||
568 | |||
569 | static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx) | ||
570 | { | ||
571 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
572 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | ||
573 | if (((sw->pre_highest_stage == hw->end_stage) && | ||
574 | (sw->highest_stage == hw->start_stage)) || | ||
575 | ((sw->pre_highest_stage == hw->start_stage) && | ||
576 | (sw->highest_stage == hw->end_stage))) | ||
577 | sw->flt_pos = sw->abs_pos; | ||
578 | else | ||
579 | sw->flt_pos = ((sw->flt_pos * 30) + (sw->abs_pos * 71)) / 100; | ||
580 | |||
581 | if (sw->flt_pos > hw->max_coord) | ||
582 | sw->flt_pos = hw->max_coord; | ||
583 | } | ||
584 | |||
585 | static void ad714x_wheel_use_com_int(struct ad714x_chip *ad714x, int idx) | ||
586 | { | ||
587 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
588 | |||
589 | ad714x_use_com_int(ad714x, hw->start_stage, hw->end_stage); | ||
590 | } | ||
591 | |||
592 | static void ad714x_wheel_use_thr_int(struct ad714x_chip *ad714x, int idx) | ||
593 | { | ||
594 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
595 | |||
596 | ad714x_use_thr_int(ad714x, hw->start_stage, hw->end_stage); | ||
597 | } | ||
598 | |||
599 | static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx) | ||
600 | { | ||
601 | struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx]; | ||
602 | struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx]; | ||
603 | unsigned short h_state, c_state; | ||
604 | unsigned short mask; | ||
605 | |||
606 | mask = ((1 << (hw->end_stage + 1)) - 1) - ((1 << hw->start_stage) - 1); | ||
607 | |||
608 | h_state = ad714x->h_state & mask; | ||
609 | c_state = ad714x->c_state & mask; | ||
610 | |||
611 | switch (sw->state) { | ||
612 | case IDLE: | ||
613 | if (h_state) { | ||
614 | sw->state = JITTER; | ||
615 | /* In End of Conversion interrupt mode, the AD714X | ||
616 | * continuously generates hardware interrupts. | ||
617 | */ | ||
618 | ad714x_wheel_use_com_int(ad714x, idx); | ||
619 | dev_dbg(ad714x->dev, "wheel %d touched\n", idx); | ||
620 | } | ||
621 | break; | ||
622 | |||
623 | case JITTER: | ||
624 | if (c_state == mask) { | ||
625 | ad714x_wheel_cal_sensor_val(ad714x, idx); | ||
626 | ad714x_wheel_cal_highest_stage(ad714x, idx); | ||
627 | ad714x_wheel_cal_abs_pos(ad714x, idx); | ||
628 | sw->flt_pos = sw->abs_pos; | ||
629 | sw->state = ACTIVE; | ||
630 | } | ||
631 | break; | ||
632 | |||
633 | case ACTIVE: | ||
634 | if (c_state == mask) { | ||
635 | if (h_state) { | ||
636 | ad714x_wheel_cal_sensor_val(ad714x, idx); | ||
637 | ad714x_wheel_cal_highest_stage(ad714x, idx); | ||
638 | ad714x_wheel_cal_abs_pos(ad714x, idx); | ||
639 | ad714x_wheel_cal_flt_pos(ad714x, idx); | ||
640 | |||
641 | input_report_abs(sw->input, ABS_WHEEL, | ||
642 | sw->abs_pos); | ||
643 | input_report_key(sw->input, BTN_TOUCH, 1); | ||
644 | } else { | ||
645 | /* When the user lifts off the sensor, configure | ||
646 | * the AD714X back to threshold interrupt mode. | ||
647 | */ | ||
648 | ad714x_wheel_use_thr_int(ad714x, idx); | ||
649 | sw->state = IDLE; | ||
650 | input_report_key(sw->input, BTN_TOUCH, 0); | ||
651 | |||
652 | dev_dbg(ad714x->dev, "wheel %d released\n", | ||
653 | idx); | ||
654 | } | ||
655 | input_sync(sw->input); | ||
656 | } | ||
657 | break; | ||
658 | |||
659 | default: | ||
660 | break; | ||
661 | } | ||
662 | } | ||
663 | |||
664 | static void touchpad_cal_sensor_val(struct ad714x_chip *ad714x, int idx) | ||
665 | { | ||
666 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
667 | int i; | ||
668 | |||
669 | for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) { | ||
670 | ad714x->read(ad714x->dev, CDC_RESULT_S0 + i, | ||
671 | &ad714x->adc_reg[i]); | ||
672 | ad714x->read(ad714x->dev, | ||
673 | STAGE0_AMBIENT + i * PER_STAGE_REG_NUM, | ||
674 | &ad714x->amb_reg[i]); | ||
675 | if (ad714x->adc_reg[i] > ad714x->amb_reg[i]) | ||
676 | ad714x->sensor_val[i] = ad714x->adc_reg[i] - | ||
677 | ad714x->amb_reg[i]; | ||
678 | else | ||
679 | ad714x->sensor_val[i] = 0; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | static void touchpad_cal_highest_stage(struct ad714x_chip *ad714x, int idx) | ||
684 | { | ||
685 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
686 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
687 | |||
688 | sw->x_highest_stage = ad714x_cal_highest_stage(ad714x, | ||
689 | hw->x_start_stage, hw->x_end_stage); | ||
690 | sw->y_highest_stage = ad714x_cal_highest_stage(ad714x, | ||
691 | hw->y_start_stage, hw->y_end_stage); | ||
692 | |||
693 | dev_dbg(ad714x->dev, | ||
694 | "touchpad %d x_highest_stage:%d, y_highest_stage:%d\n", | ||
695 | idx, sw->x_highest_stage, sw->y_highest_stage); | ||
696 | } | ||
697 | |||
698 | /* | ||
699 | * If 2 fingers are touching the sensor then 2 peaks can be observed in the | ||
700 | * distribution. | ||
701 | * The arithmetic doesn't support to get absolute coordinates for multi-touch | ||
702 | * yet. | ||
703 | */ | ||
704 | static int touchpad_check_second_peak(struct ad714x_chip *ad714x, int idx) | ||
705 | { | ||
706 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
707 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
708 | int i; | ||
709 | |||
710 | for (i = hw->x_start_stage; i < sw->x_highest_stage; i++) { | ||
711 | if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1]) | ||
712 | > (ad714x->sensor_val[i + 1] / 10)) | ||
713 | return 1; | ||
714 | } | ||
715 | |||
716 | for (i = sw->x_highest_stage; i < hw->x_end_stage; i++) { | ||
717 | if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i]) | ||
718 | > (ad714x->sensor_val[i] / 10)) | ||
719 | return 1; | ||
720 | } | ||
721 | |||
722 | for (i = hw->y_start_stage; i < sw->y_highest_stage; i++) { | ||
723 | if ((ad714x->sensor_val[i] - ad714x->sensor_val[i + 1]) | ||
724 | > (ad714x->sensor_val[i + 1] / 10)) | ||
725 | return 1; | ||
726 | } | ||
727 | |||
728 | for (i = sw->y_highest_stage; i < hw->y_end_stage; i++) { | ||
729 | if ((ad714x->sensor_val[i + 1] - ad714x->sensor_val[i]) | ||
730 | > (ad714x->sensor_val[i] / 10)) | ||
731 | return 1; | ||
732 | } | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | /* | ||
738 | * If only one finger is used to activate the touch pad then only 1 peak will be | ||
739 | * registered in the distribution. This peak and the 2 adjacent sensors will be | ||
740 | * used in the calculation of the absolute position. This will prevent hand | ||
741 | * shadows to affect the absolute position calculation. | ||
742 | */ | ||
743 | static void touchpad_cal_abs_pos(struct ad714x_chip *ad714x, int idx) | ||
744 | { | ||
745 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
746 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
747 | |||
748 | sw->x_abs_pos = ad714x_cal_abs_pos(ad714x, hw->x_start_stage, | ||
749 | hw->x_end_stage, sw->x_highest_stage, hw->x_max_coord); | ||
750 | sw->y_abs_pos = ad714x_cal_abs_pos(ad714x, hw->y_start_stage, | ||
751 | hw->y_end_stage, sw->y_highest_stage, hw->y_max_coord); | ||
752 | |||
753 | dev_dbg(ad714x->dev, "touchpad %d absolute position:(%d, %d)\n", idx, | ||
754 | sw->x_abs_pos, sw->y_abs_pos); | ||
755 | } | ||
756 | |||
757 | static void touchpad_cal_flt_pos(struct ad714x_chip *ad714x, int idx) | ||
758 | { | ||
759 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
760 | |||
761 | sw->x_flt_pos = (sw->x_flt_pos * (10 - 4) + | ||
762 | sw->x_abs_pos * 4)/10; | ||
763 | sw->y_flt_pos = (sw->y_flt_pos * (10 - 4) + | ||
764 | sw->y_abs_pos * 4)/10; | ||
765 | |||
766 | dev_dbg(ad714x->dev, "touchpad %d filter position:(%d, %d)\n", | ||
767 | idx, sw->x_flt_pos, sw->y_flt_pos); | ||
768 | } | ||
769 | |||
770 | /* | ||
771 | * To prevent distortion from showing in the absolute position, it is | ||
772 | * necessary to detect the end points. When endpoints are detected, the | ||
773 | * driver stops updating the status variables with absolute positions. | ||
774 | * End points are detected on the 4 edges of the touchpad sensor. The | ||
775 | * method to detect them is the same for all 4. | ||
776 | * To detect the end points, the firmware computes the difference in | ||
777 | * percent between the sensor on the edge and the adjacent one. The | ||
778 | * difference is calculated in percent in order to make the end point | ||
779 | * detection independent of the pressure. | ||
780 | */ | ||
781 | |||
782 | #define LEFT_END_POINT_DETECTION_LEVEL 550 | ||
783 | #define RIGHT_END_POINT_DETECTION_LEVEL 750 | ||
784 | #define LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL 850 | ||
785 | #define TOP_END_POINT_DETECTION_LEVEL 550 | ||
786 | #define BOTTOM_END_POINT_DETECTION_LEVEL 950 | ||
787 | #define TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL 700 | ||
788 | static int touchpad_check_endpoint(struct ad714x_chip *ad714x, int idx) | ||
789 | { | ||
790 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
791 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
792 | int percent_sensor_diff; | ||
793 | |||
794 | /* left endpoint detect */ | ||
795 | percent_sensor_diff = (ad714x->sensor_val[hw->x_start_stage] - | ||
796 | ad714x->sensor_val[hw->x_start_stage + 1]) * 100 / | ||
797 | ad714x->sensor_val[hw->x_start_stage + 1]; | ||
798 | if (!sw->left_ep) { | ||
799 | if (percent_sensor_diff >= LEFT_END_POINT_DETECTION_LEVEL) { | ||
800 | sw->left_ep = 1; | ||
801 | sw->left_ep_val = | ||
802 | ad714x->sensor_val[hw->x_start_stage + 1]; | ||
803 | } | ||
804 | } else { | ||
805 | if ((percent_sensor_diff < LEFT_END_POINT_DETECTION_LEVEL) && | ||
806 | (ad714x->sensor_val[hw->x_start_stage + 1] > | ||
807 | LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->left_ep_val)) | ||
808 | sw->left_ep = 0; | ||
809 | } | ||
810 | |||
811 | /* right endpoint detect */ | ||
812 | percent_sensor_diff = (ad714x->sensor_val[hw->x_end_stage] - | ||
813 | ad714x->sensor_val[hw->x_end_stage - 1]) * 100 / | ||
814 | ad714x->sensor_val[hw->x_end_stage - 1]; | ||
815 | if (!sw->right_ep) { | ||
816 | if (percent_sensor_diff >= RIGHT_END_POINT_DETECTION_LEVEL) { | ||
817 | sw->right_ep = 1; | ||
818 | sw->right_ep_val = | ||
819 | ad714x->sensor_val[hw->x_end_stage - 1]; | ||
820 | } | ||
821 | } else { | ||
822 | if ((percent_sensor_diff < RIGHT_END_POINT_DETECTION_LEVEL) && | ||
823 | (ad714x->sensor_val[hw->x_end_stage - 1] > | ||
824 | LEFT_RIGHT_END_POINT_DEAVTIVALION_LEVEL + sw->right_ep_val)) | ||
825 | sw->right_ep = 0; | ||
826 | } | ||
827 | |||
828 | /* top endpoint detect */ | ||
829 | percent_sensor_diff = (ad714x->sensor_val[hw->y_start_stage] - | ||
830 | ad714x->sensor_val[hw->y_start_stage + 1]) * 100 / | ||
831 | ad714x->sensor_val[hw->y_start_stage + 1]; | ||
832 | if (!sw->top_ep) { | ||
833 | if (percent_sensor_diff >= TOP_END_POINT_DETECTION_LEVEL) { | ||
834 | sw->top_ep = 1; | ||
835 | sw->top_ep_val = | ||
836 | ad714x->sensor_val[hw->y_start_stage + 1]; | ||
837 | } | ||
838 | } else { | ||
839 | if ((percent_sensor_diff < TOP_END_POINT_DETECTION_LEVEL) && | ||
840 | (ad714x->sensor_val[hw->y_start_stage + 1] > | ||
841 | TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->top_ep_val)) | ||
842 | sw->top_ep = 0; | ||
843 | } | ||
844 | |||
845 | /* bottom endpoint detect */ | ||
846 | percent_sensor_diff = (ad714x->sensor_val[hw->y_end_stage] - | ||
847 | ad714x->sensor_val[hw->y_end_stage - 1]) * 100 / | ||
848 | ad714x->sensor_val[hw->y_end_stage - 1]; | ||
849 | if (!sw->bottom_ep) { | ||
850 | if (percent_sensor_diff >= BOTTOM_END_POINT_DETECTION_LEVEL) { | ||
851 | sw->bottom_ep = 1; | ||
852 | sw->bottom_ep_val = | ||
853 | ad714x->sensor_val[hw->y_end_stage - 1]; | ||
854 | } | ||
855 | } else { | ||
856 | if ((percent_sensor_diff < BOTTOM_END_POINT_DETECTION_LEVEL) && | ||
857 | (ad714x->sensor_val[hw->y_end_stage - 1] > | ||
858 | TOP_BOTTOM_END_POINT_DEAVTIVALION_LEVEL + sw->bottom_ep_val)) | ||
859 | sw->bottom_ep = 0; | ||
860 | } | ||
861 | |||
862 | return sw->left_ep || sw->right_ep || sw->top_ep || sw->bottom_ep; | ||
863 | } | ||
864 | |||
865 | static void touchpad_use_com_int(struct ad714x_chip *ad714x, int idx) | ||
866 | { | ||
867 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
868 | |||
869 | ad714x_use_com_int(ad714x, hw->x_start_stage, hw->x_end_stage); | ||
870 | } | ||
871 | |||
872 | static void touchpad_use_thr_int(struct ad714x_chip *ad714x, int idx) | ||
873 | { | ||
874 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
875 | |||
876 | ad714x_use_thr_int(ad714x, hw->x_start_stage, hw->x_end_stage); | ||
877 | ad714x_use_thr_int(ad714x, hw->y_start_stage, hw->y_end_stage); | ||
878 | } | ||
879 | |||
880 | static void ad714x_touchpad_state_machine(struct ad714x_chip *ad714x, int idx) | ||
881 | { | ||
882 | struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx]; | ||
883 | struct ad714x_touchpad_drv *sw = &ad714x->sw->touchpad[idx]; | ||
884 | unsigned short h_state, c_state; | ||
885 | unsigned short mask; | ||
886 | |||
887 | mask = (((1 << (hw->x_end_stage + 1)) - 1) - | ||
888 | ((1 << hw->x_start_stage) - 1)) + | ||
889 | (((1 << (hw->y_end_stage + 1)) - 1) - | ||
890 | ((1 << hw->y_start_stage) - 1)); | ||
891 | |||
892 | h_state = ad714x->h_state & mask; | ||
893 | c_state = ad714x->c_state & mask; | ||
894 | |||
895 | switch (sw->state) { | ||
896 | case IDLE: | ||
897 | if (h_state) { | ||
898 | sw->state = JITTER; | ||
899 | /* In End of Conversion interrupt mode, the AD714X | ||
900 | * continuously generates hardware interrupts. | ||
901 | */ | ||
902 | touchpad_use_com_int(ad714x, idx); | ||
903 | dev_dbg(ad714x->dev, "touchpad %d touched\n", idx); | ||
904 | } | ||
905 | break; | ||
906 | |||
907 | case JITTER: | ||
908 | if (c_state == mask) { | ||
909 | touchpad_cal_sensor_val(ad714x, idx); | ||
910 | touchpad_cal_highest_stage(ad714x, idx); | ||
911 | if ((!touchpad_check_second_peak(ad714x, idx)) && | ||
912 | (!touchpad_check_endpoint(ad714x, idx))) { | ||
913 | dev_dbg(ad714x->dev, | ||
914 | "touchpad%d, 2 fingers or endpoint\n", | ||
915 | idx); | ||
916 | touchpad_cal_abs_pos(ad714x, idx); | ||
917 | sw->x_flt_pos = sw->x_abs_pos; | ||
918 | sw->y_flt_pos = sw->y_abs_pos; | ||
919 | sw->state = ACTIVE; | ||
920 | } | ||
921 | } | ||
922 | break; | ||
923 | |||
924 | case ACTIVE: | ||
925 | if (c_state == mask) { | ||
926 | if (h_state) { | ||
927 | touchpad_cal_sensor_val(ad714x, idx); | ||
928 | touchpad_cal_highest_stage(ad714x, idx); | ||
929 | if ((!touchpad_check_second_peak(ad714x, idx)) | ||
930 | && (!touchpad_check_endpoint(ad714x, idx))) { | ||
931 | touchpad_cal_abs_pos(ad714x, idx); | ||
932 | touchpad_cal_flt_pos(ad714x, idx); | ||
933 | input_report_abs(sw->input, ABS_X, | ||
934 | sw->x_flt_pos); | ||
935 | input_report_abs(sw->input, ABS_Y, | ||
936 | sw->y_flt_pos); | ||
937 | input_report_key(sw->input, BTN_TOUCH, | ||
938 | 1); | ||
939 | } | ||
940 | } else { | ||
941 | /* When the user lifts off the sensor, configure | ||
942 | * the AD714X back to threshold interrupt mode. | ||
943 | */ | ||
944 | touchpad_use_thr_int(ad714x, idx); | ||
945 | sw->state = IDLE; | ||
946 | input_report_key(sw->input, BTN_TOUCH, 0); | ||
947 | dev_dbg(ad714x->dev, "touchpad %d released\n", | ||
948 | idx); | ||
949 | } | ||
950 | input_sync(sw->input); | ||
951 | } | ||
952 | break; | ||
953 | |||
954 | default: | ||
955 | break; | ||
956 | } | ||
957 | } | ||
958 | |||
959 | static int ad714x_hw_detect(struct ad714x_chip *ad714x) | ||
960 | { | ||
961 | unsigned short data; | ||
962 | |||
963 | ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data); | ||
964 | switch (data & 0xFFF0) { | ||
965 | case AD7147_PARTID: | ||
966 | ad714x->product = 0x7147; | ||
967 | ad714x->version = data & 0xF; | ||
968 | dev_info(ad714x->dev, "found AD7147 captouch, rev:%d\n", | ||
969 | ad714x->version); | ||
970 | return 0; | ||
971 | |||
972 | case AD7142_PARTID: | ||
973 | ad714x->product = 0x7142; | ||
974 | ad714x->version = data & 0xF; | ||
975 | dev_info(ad714x->dev, "found AD7142 captouch, rev:%d\n", | ||
976 | ad714x->version); | ||
977 | return 0; | ||
978 | |||
979 | default: | ||
980 | dev_err(ad714x->dev, | ||
981 | "fail to detect AD714X captouch, read ID is %04x\n", | ||
982 | data); | ||
983 | return -ENODEV; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | static void ad714x_hw_init(struct ad714x_chip *ad714x) | ||
988 | { | ||
989 | int i, j; | ||
990 | unsigned short reg_base; | ||
991 | unsigned short data; | ||
992 | |||
993 | /* configuration CDC and interrupts */ | ||
994 | |||
995 | for (i = 0; i < STAGE_NUM; i++) { | ||
996 | reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM; | ||
997 | for (j = 0; j < STAGE_CFGREG_NUM; j++) | ||
998 | ad714x->write(ad714x->dev, reg_base + j, | ||
999 | ad714x->hw->stage_cfg_reg[i][j]); | ||
1000 | } | ||
1001 | |||
1002 | for (i = 0; i < SYS_CFGREG_NUM; i++) | ||
1003 | ad714x->write(ad714x->dev, AD714X_SYSCFG_REG + i, | ||
1004 | ad714x->hw->sys_cfg_reg[i]); | ||
1005 | for (i = 0; i < SYS_CFGREG_NUM; i++) | ||
1006 | ad714x->read(ad714x->dev, AD714X_SYSCFG_REG + i, | ||
1007 | &data); | ||
1008 | |||
1009 | ad714x->write(ad714x->dev, AD714X_STG_CAL_EN_REG, 0xFFF); | ||
1010 | |||
1011 | /* clear all interrupts */ | ||
1012 | ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data); | ||
1013 | ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data); | ||
1014 | ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data); | ||
1015 | } | ||
1016 | |||
1017 | static irqreturn_t ad714x_interrupt_thread(int irq, void *data) | ||
1018 | { | ||
1019 | struct ad714x_chip *ad714x = data; | ||
1020 | int i; | ||
1021 | |||
1022 | mutex_lock(&ad714x->mutex); | ||
1023 | |||
1024 | ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &ad714x->l_state); | ||
1025 | ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &ad714x->h_state); | ||
1026 | ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &ad714x->c_state); | ||
1027 | |||
1028 | for (i = 0; i < ad714x->hw->button_num; i++) | ||
1029 | ad714x_button_state_machine(ad714x, i); | ||
1030 | for (i = 0; i < ad714x->hw->slider_num; i++) | ||
1031 | ad714x_slider_state_machine(ad714x, i); | ||
1032 | for (i = 0; i < ad714x->hw->wheel_num; i++) | ||
1033 | ad714x_wheel_state_machine(ad714x, i); | ||
1034 | for (i = 0; i < ad714x->hw->touchpad_num; i++) | ||
1035 | ad714x_touchpad_state_machine(ad714x, i); | ||
1036 | |||
1037 | mutex_unlock(&ad714x->mutex); | ||
1038 | |||
1039 | return IRQ_HANDLED; | ||
1040 | } | ||
1041 | |||
1042 | #define MAX_DEVICE_NUM 8 | ||
1043 | struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq, | ||
1044 | ad714x_read_t read, ad714x_write_t write) | ||
1045 | { | ||
1046 | int i, alloc_idx; | ||
1047 | int error; | ||
1048 | struct input_dev *input[MAX_DEVICE_NUM]; | ||
1049 | |||
1050 | struct ad714x_platform_data *plat_data = dev->platform_data; | ||
1051 | struct ad714x_chip *ad714x; | ||
1052 | void *drv_mem; | ||
1053 | |||
1054 | struct ad714x_button_drv *bt_drv; | ||
1055 | struct ad714x_slider_drv *sd_drv; | ||
1056 | struct ad714x_wheel_drv *wl_drv; | ||
1057 | struct ad714x_touchpad_drv *tp_drv; | ||
1058 | |||
1059 | |||
1060 | if (irq <= 0) { | ||
1061 | dev_err(dev, "IRQ not configured!\n"); | ||
1062 | error = -EINVAL; | ||
1063 | goto err_out; | ||
1064 | } | ||
1065 | |||
1066 | if (dev->platform_data == NULL) { | ||
1067 | dev_err(dev, "platform data for ad714x doesn't exist\n"); | ||
1068 | error = -EINVAL; | ||
1069 | goto err_out; | ||
1070 | } | ||
1071 | |||
1072 | ad714x = kzalloc(sizeof(*ad714x) + sizeof(*ad714x->sw) + | ||
1073 | sizeof(*sd_drv) * plat_data->slider_num + | ||
1074 | sizeof(*wl_drv) * plat_data->wheel_num + | ||
1075 | sizeof(*tp_drv) * plat_data->touchpad_num + | ||
1076 | sizeof(*bt_drv) * plat_data->button_num, GFP_KERNEL); | ||
1077 | if (!ad714x) { | ||
1078 | error = -ENOMEM; | ||
1079 | goto err_out; | ||
1080 | } | ||
1081 | |||
1082 | ad714x->hw = plat_data; | ||
1083 | |||
1084 | drv_mem = ad714x + 1; | ||
1085 | ad714x->sw = drv_mem; | ||
1086 | drv_mem += sizeof(*ad714x->sw); | ||
1087 | ad714x->sw->slider = sd_drv = drv_mem; | ||
1088 | drv_mem += sizeof(*sd_drv) * ad714x->hw->slider_num; | ||
1089 | ad714x->sw->wheel = wl_drv = drv_mem; | ||
1090 | drv_mem += sizeof(*wl_drv) * ad714x->hw->wheel_num; | ||
1091 | ad714x->sw->touchpad = tp_drv = drv_mem; | ||
1092 | drv_mem += sizeof(*tp_drv) * ad714x->hw->touchpad_num; | ||
1093 | ad714x->sw->button = bt_drv = drv_mem; | ||
1094 | drv_mem += sizeof(*bt_drv) * ad714x->hw->button_num; | ||
1095 | |||
1096 | ad714x->read = read; | ||
1097 | ad714x->write = write; | ||
1098 | ad714x->irq = irq; | ||
1099 | ad714x->dev = dev; | ||
1100 | |||
1101 | error = ad714x_hw_detect(ad714x); | ||
1102 | if (error) | ||
1103 | goto err_free_mem; | ||
1104 | |||
1105 | /* initilize and request sw/hw resources */ | ||
1106 | |||
1107 | ad714x_hw_init(ad714x); | ||
1108 | mutex_init(&ad714x->mutex); | ||
1109 | |||
1110 | /* | ||
1111 | * Allocate and register AD714X input device | ||
1112 | */ | ||
1113 | alloc_idx = 0; | ||
1114 | |||
1115 | /* a slider uses one input_dev instance */ | ||
1116 | if (ad714x->hw->slider_num > 0) { | ||
1117 | struct ad714x_slider_plat *sd_plat = ad714x->hw->slider; | ||
1118 | |||
1119 | for (i = 0; i < ad714x->hw->slider_num; i++) { | ||
1120 | sd_drv[i].input = input[alloc_idx] = input_allocate_device(); | ||
1121 | if (!input[alloc_idx]) { | ||
1122 | error = -ENOMEM; | ||
1123 | goto err_free_dev; | ||
1124 | } | ||
1125 | |||
1126 | __set_bit(EV_ABS, input[alloc_idx]->evbit); | ||
1127 | __set_bit(EV_KEY, input[alloc_idx]->evbit); | ||
1128 | __set_bit(ABS_X, input[alloc_idx]->absbit); | ||
1129 | __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); | ||
1130 | input_set_abs_params(input[alloc_idx], | ||
1131 | ABS_X, 0, sd_plat->max_coord, 0, 0); | ||
1132 | |||
1133 | input[alloc_idx]->id.bustype = bus_type; | ||
1134 | input[alloc_idx]->id.product = ad714x->product; | ||
1135 | input[alloc_idx]->id.version = ad714x->version; | ||
1136 | |||
1137 | error = input_register_device(input[alloc_idx]); | ||
1138 | if (error) | ||
1139 | goto err_free_dev; | ||
1140 | |||
1141 | alloc_idx++; | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | /* a wheel uses one input_dev instance */ | ||
1146 | if (ad714x->hw->wheel_num > 0) { | ||
1147 | struct ad714x_wheel_plat *wl_plat = ad714x->hw->wheel; | ||
1148 | |||
1149 | for (i = 0; i < ad714x->hw->wheel_num; i++) { | ||
1150 | wl_drv[i].input = input[alloc_idx] = input_allocate_device(); | ||
1151 | if (!input[alloc_idx]) { | ||
1152 | error = -ENOMEM; | ||
1153 | goto err_free_dev; | ||
1154 | } | ||
1155 | |||
1156 | __set_bit(EV_KEY, input[alloc_idx]->evbit); | ||
1157 | __set_bit(EV_ABS, input[alloc_idx]->evbit); | ||
1158 | __set_bit(ABS_WHEEL, input[alloc_idx]->absbit); | ||
1159 | __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); | ||
1160 | input_set_abs_params(input[alloc_idx], | ||
1161 | ABS_WHEEL, 0, wl_plat->max_coord, 0, 0); | ||
1162 | |||
1163 | input[alloc_idx]->id.bustype = bus_type; | ||
1164 | input[alloc_idx]->id.product = ad714x->product; | ||
1165 | input[alloc_idx]->id.version = ad714x->version; | ||
1166 | |||
1167 | error = input_register_device(input[alloc_idx]); | ||
1168 | if (error) | ||
1169 | goto err_free_dev; | ||
1170 | |||
1171 | alloc_idx++; | ||
1172 | } | ||
1173 | } | ||
1174 | |||
1175 | /* a touchpad uses one input_dev instance */ | ||
1176 | if (ad714x->hw->touchpad_num > 0) { | ||
1177 | struct ad714x_touchpad_plat *tp_plat = ad714x->hw->touchpad; | ||
1178 | |||
1179 | for (i = 0; i < ad714x->hw->touchpad_num; i++) { | ||
1180 | tp_drv[i].input = input[alloc_idx] = input_allocate_device(); | ||
1181 | if (!input[alloc_idx]) { | ||
1182 | error = -ENOMEM; | ||
1183 | goto err_free_dev; | ||
1184 | } | ||
1185 | |||
1186 | __set_bit(EV_ABS, input[alloc_idx]->evbit); | ||
1187 | __set_bit(EV_KEY, input[alloc_idx]->evbit); | ||
1188 | __set_bit(ABS_X, input[alloc_idx]->absbit); | ||
1189 | __set_bit(ABS_Y, input[alloc_idx]->absbit); | ||
1190 | __set_bit(BTN_TOUCH, input[alloc_idx]->keybit); | ||
1191 | input_set_abs_params(input[alloc_idx], | ||
1192 | ABS_X, 0, tp_plat->x_max_coord, 0, 0); | ||
1193 | input_set_abs_params(input[alloc_idx], | ||
1194 | ABS_Y, 0, tp_plat->y_max_coord, 0, 0); | ||
1195 | |||
1196 | input[alloc_idx]->id.bustype = bus_type; | ||
1197 | input[alloc_idx]->id.product = ad714x->product; | ||
1198 | input[alloc_idx]->id.version = ad714x->version; | ||
1199 | |||
1200 | error = input_register_device(input[alloc_idx]); | ||
1201 | if (error) | ||
1202 | goto err_free_dev; | ||
1203 | |||
1204 | alloc_idx++; | ||
1205 | } | ||
1206 | } | ||
1207 | |||
1208 | /* all buttons use one input node */ | ||
1209 | if (ad714x->hw->button_num > 0) { | ||
1210 | struct ad714x_button_plat *bt_plat = ad714x->hw->button; | ||
1211 | |||
1212 | input[alloc_idx] = input_allocate_device(); | ||
1213 | if (!input[alloc_idx]) { | ||
1214 | error = -ENOMEM; | ||
1215 | goto err_free_dev; | ||
1216 | } | ||
1217 | |||
1218 | __set_bit(EV_KEY, input[alloc_idx]->evbit); | ||
1219 | for (i = 0; i < ad714x->hw->button_num; i++) { | ||
1220 | bt_drv[i].input = input[alloc_idx]; | ||
1221 | __set_bit(bt_plat[i].keycode, input[alloc_idx]->keybit); | ||
1222 | } | ||
1223 | |||
1224 | input[alloc_idx]->id.bustype = bus_type; | ||
1225 | input[alloc_idx]->id.product = ad714x->product; | ||
1226 | input[alloc_idx]->id.version = ad714x->version; | ||
1227 | |||
1228 | error = input_register_device(input[alloc_idx]); | ||
1229 | if (error) | ||
1230 | goto err_free_dev; | ||
1231 | |||
1232 | alloc_idx++; | ||
1233 | } | ||
1234 | |||
1235 | error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread, | ||
1236 | IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x); | ||
1237 | if (error) { | ||
1238 | dev_err(dev, "can't allocate irq %d\n", ad714x->irq); | ||
1239 | goto err_unreg_dev; | ||
1240 | } | ||
1241 | |||
1242 | return ad714x; | ||
1243 | |||
1244 | err_free_dev: | ||
1245 | dev_err(dev, "failed to setup AD714x input device %i\n", alloc_idx); | ||
1246 | input_free_device(input[alloc_idx]); | ||
1247 | err_unreg_dev: | ||
1248 | while (--alloc_idx >= 0) | ||
1249 | input_unregister_device(input[alloc_idx]); | ||
1250 | err_free_mem: | ||
1251 | kfree(ad714x); | ||
1252 | err_out: | ||
1253 | return ERR_PTR(error); | ||
1254 | } | ||
1255 | EXPORT_SYMBOL(ad714x_probe); | ||
1256 | |||
1257 | void ad714x_remove(struct ad714x_chip *ad714x) | ||
1258 | { | ||
1259 | struct ad714x_platform_data *hw = ad714x->hw; | ||
1260 | struct ad714x_driver_data *sw = ad714x->sw; | ||
1261 | int i; | ||
1262 | |||
1263 | free_irq(ad714x->irq, ad714x); | ||
1264 | |||
1265 | /* unregister and free all input devices */ | ||
1266 | |||
1267 | for (i = 0; i < hw->slider_num; i++) | ||
1268 | input_unregister_device(sw->slider[i].input); | ||
1269 | |||
1270 | for (i = 0; i < hw->wheel_num; i++) | ||
1271 | input_unregister_device(sw->wheel[i].input); | ||
1272 | |||
1273 | for (i = 0; i < hw->touchpad_num; i++) | ||
1274 | input_unregister_device(sw->touchpad[i].input); | ||
1275 | |||
1276 | if (hw->button_num) | ||
1277 | input_unregister_device(sw->button[0].input); | ||
1278 | |||
1279 | kfree(ad714x); | ||
1280 | } | ||
1281 | EXPORT_SYMBOL(ad714x_remove); | ||
1282 | |||
1283 | #ifdef CONFIG_PM | ||
1284 | int ad714x_disable(struct ad714x_chip *ad714x) | ||
1285 | { | ||
1286 | unsigned short data; | ||
1287 | |||
1288 | dev_dbg(ad714x->dev, "%s enter\n", __func__); | ||
1289 | |||
1290 | mutex_lock(&ad714x->mutex); | ||
1291 | |||
1292 | data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3; | ||
1293 | ad714x->write(ad714x->dev, AD714X_PWR_CTRL, data); | ||
1294 | |||
1295 | mutex_unlock(&ad714x->mutex); | ||
1296 | |||
1297 | return 0; | ||
1298 | } | ||
1299 | EXPORT_SYMBOL(ad714x_disable); | ||
1300 | |||
1301 | int ad714x_enable(struct ad714x_chip *ad714x) | ||
1302 | { | ||
1303 | unsigned short data; | ||
1304 | |||
1305 | dev_dbg(ad714x->dev, "%s enter\n", __func__); | ||
1306 | |||
1307 | mutex_lock(&ad714x->mutex); | ||
1308 | |||
1309 | /* resume to non-shutdown mode */ | ||
1310 | |||
1311 | ad714x->write(ad714x->dev, AD714X_PWR_CTRL, | ||
1312 | ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]); | ||
1313 | |||
1314 | /* make sure the interrupt output line is not low level after resume, | ||
1315 | * otherwise we will get no chance to enter falling-edge irq again | ||
1316 | */ | ||
1317 | |||
1318 | ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data); | ||
1319 | ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data); | ||
1320 | ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data); | ||
1321 | |||
1322 | mutex_unlock(&ad714x->mutex); | ||
1323 | |||
1324 | return 0; | ||
1325 | } | ||
1326 | EXPORT_SYMBOL(ad714x_enable); | ||
1327 | #endif | ||
1328 | |||
1329 | MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver"); | ||
1330 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
1331 | MODULE_LICENSE("GPL"); | ||