Merge branch 'develop' of xwj@10.10.10.201:/home/rockchip/rk2818/kernel into develop
[firefly-linux-kernel-4.4.55.git] / drivers / input / touchscreen / calibration_ts.c
1 /*\r
2  * drivers/input/touchscreen/calibration_ts.c - calibration for rk2818 spi xpt2046 device and console\r
3  *\r
4  * Copyright (C) 2010 ROCKCHIP, Inc.\r
5  *\r
6  * This software is licensed under the terms of the GNU General Public\r
7  * License version 2, as published by the Free Software Foundation, and\r
8  * may be copied, distributed, and modified under those terms.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  */\r
15 #include <linux/kernel.h>\r
16 #include <linux/string.h>\r
17 \r
18 #include "calibration_ts.h"\r
19 #include "largenum_ts.h"\r
20 \r
21 #define MAX_POINT_ERROR 6\r
22 \r
23 typedef struct {\r
24     PLARGENUM   pa11, pa12, pa13;\r
25     PLARGENUM   pa21, pa22, pa23;\r
26     PLARGENUM   pa31, pa32, pa33;\r
27 }   MATRIX33, *PMATRIX33;\r
28 \r
29 typedef struct {\r
30     int   a1;\r
31     int   b1;\r
32     int   c1;\r
33     int   a2;\r
34     int   b2;\r
35     int   c2;\r
36     int   delta;\r
37 }   \r
38 CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER;\r
39 \r
40 static unsigned char            v_Calibrated = 0;\r
41 static CALIBRATION_PARAMETER    v_CalcParam;\r
42 \r
43 unsigned char\r
44 ErrorAnalysis(\r
45     int   cCalibrationPoints,     //@PARM The number of calibration points\r
46     int   *pScreenXBuffer,        //@PARM List of screen X coords displayed\r
47     int   *pScreenYBuffer,        //@PARM List of screen Y coords displayed\r
48     int   *pUncalXBuffer,         //@PARM List of X coords collected\r
49     int   *pUncalYBuffer          //@PARM List of Y coords collected\r
50     );\r
51 \r
52 void\r
53 ComputeMatrix33(\r
54     PLARGENUM   pResult,\r
55     PMATRIX33   pMatrix\r
56     );\r
57 \r
58 unsigned char\r
59 TouchPanelSetCalibration(\r
60     int   cCalibrationPoints,     //@PARM The number of calibration points\r
61     int   *pScreenXBuffer,        //@PARM List of screen X coords displayed\r
62     int   *pScreenYBuffer,        //@PARM List of screen Y coords displayed\r
63     int   *pUncalXBuffer,         //@PARM List of X coords collected\r
64     int   *pUncalYBuffer          //@PARM List of Y coords collected\r
65     )\r
66 {\r
67     LARGENUM    a11;\r
68     LARGENUM    a21, a22;\r
69     LARGENUM    a31, a32, a33;\r
70     LARGENUM    b11, b12, b13;\r
71     LARGENUM    b21, b22, b23;\r
72     LARGENUM    lnScreenX;\r
73     LARGENUM    lnScreenY;\r
74     LARGENUM    lnTouchX;\r
75     LARGENUM    lnTouchY;\r
76     LARGENUM    lnTemp;\r
77     LARGENUM    delta;\r
78     LARGENUM    a1, b1, c1;\r
79     LARGENUM    a2, b2, c2;\r
80     MATRIX33    Matrix;\r
81     int       cShift;\r
82     int       minShift;\r
83     int         i;\r
84 \r
85 \r
86     //DEBUGMSG(1,(__TEXT("calibrating %d point set\r\n"), cCalibrationPoints));\r
87 \r
88      //\r
89      // If the calibration data is being cleared, set the flag so\r
90      // that the conversion operation is a noop.\r
91      //\r
92 \r
93     if ( cCalibrationPoints == 0 )\r
94     {\r
95         v_Calibrated = 0;\r
96         return 1;\r
97     }\r
98 \r
99     //\r
100     // Compute these large numbers\r
101     //\r
102     LargeNumSet(&a11, 0);\r
103     LargeNumSet(&a21, 0);\r
104     LargeNumSet(&a31, 0);\r
105     LargeNumSet(&a22, 0);\r
106     LargeNumSet(&a32, 0);\r
107     LargeNumSet(&a33, cCalibrationPoints);\r
108     LargeNumSet(&b11, 0);\r
109     LargeNumSet(&b12, 0);\r
110     LargeNumSet(&b13, 0);\r
111     LargeNumSet(&b21, 0);\r
112     LargeNumSet(&b22, 0);\r
113     LargeNumSet(&b23, 0);\r
114     for(i=0; i<cCalibrationPoints; i++){\r
115         LargeNumSet(&lnTouchX, pUncalXBuffer[i]);\r
116         LargeNumSet(&lnTouchY, pUncalYBuffer[i]);\r
117         LargeNumSet(&lnScreenX, pScreenXBuffer[i]);\r
118         LargeNumSet(&lnScreenY, pScreenYBuffer[i]);\r
119         LargeNumMult(&lnTouchX, &lnTouchX, &lnTemp);\r
120         LargeNumAdd(&a11, &lnTemp, &a11);\r
121         LargeNumMult(&lnTouchX, &lnTouchY, &lnTemp);\r
122         LargeNumAdd(&a21, &lnTemp, &a21);\r
123         LargeNumAdd(&a31, &lnTouchX, &a31);\r
124         LargeNumMult(&lnTouchY, &lnTouchY, &lnTemp);\r
125         LargeNumAdd(&a22, &lnTemp, &a22);\r
126         LargeNumAdd(&a32, &lnTouchY, &a32);\r
127         LargeNumMult(&lnTouchX, &lnScreenX, &lnTemp);\r
128         LargeNumAdd(&b11, &lnTemp, &b11);\r
129         LargeNumMult(&lnTouchY, &lnScreenX, &lnTemp);\r
130         LargeNumAdd(&b12, &lnTemp, &b12);\r
131         LargeNumAdd(&b13, &lnScreenX, &b13);\r
132         LargeNumMult(&lnTouchX, &lnScreenY, &lnTemp);\r
133         LargeNumAdd(&b21, &lnTemp, &b21);\r
134         LargeNumMult(&lnTouchY, &lnScreenY, &lnTemp);\r
135         LargeNumAdd(&b22, &lnTemp, &b22);\r
136         LargeNumAdd(&b23, &lnScreenY, &b23);\r
137     }\r
138 \r
139     Matrix.pa11 = &a11;\r
140     Matrix.pa21 = &a21;\r
141     Matrix.pa31 = &a31;\r
142     Matrix.pa12 = &a21;\r
143     Matrix.pa22 = &a22;\r
144     Matrix.pa32 = &a32;\r
145     Matrix.pa13 = &a31;\r
146     Matrix.pa23 = &a32;\r
147     Matrix.pa33 = &a33;\r
148     ComputeMatrix33(&delta, &Matrix);\r
149 \r
150     Matrix.pa11 = &b11;\r
151     Matrix.pa21 = &b12;\r
152     Matrix.pa31 = &b13;\r
153     ComputeMatrix33(&a1, &Matrix);\r
154 \r
155     Matrix.pa11 = &a11;\r
156     Matrix.pa21 = &a21;\r
157     Matrix.pa31 = &a31;\r
158     Matrix.pa12 = &b11;\r
159     Matrix.pa22 = &b12;\r
160     Matrix.pa32 = &b13;\r
161     ComputeMatrix33(&b1, &Matrix);\r
162 \r
163     Matrix.pa12 = &a21;\r
164     Matrix.pa22 = &a22;\r
165     Matrix.pa32 = &a32;\r
166     Matrix.pa13 = &b11;\r
167     Matrix.pa23 = &b12;\r
168     Matrix.pa33 = &b13;\r
169     ComputeMatrix33(&c1, &Matrix);\r
170 \r
171     Matrix.pa13 = &a31;\r
172     Matrix.pa23 = &a32;\r
173     Matrix.pa33 = &a33;\r
174     Matrix.pa11 = &b21;\r
175     Matrix.pa21 = &b22;\r
176     Matrix.pa31 = &b23;\r
177     ComputeMatrix33(&a2, &Matrix);\r
178 \r
179     Matrix.pa11 = &a11;\r
180     Matrix.pa21 = &a21;\r
181     Matrix.pa31 = &a31;\r
182     Matrix.pa12 = &b21;\r
183     Matrix.pa22 = &b22;\r
184     Matrix.pa32 = &b23;\r
185     ComputeMatrix33(&b2, &Matrix);\r
186 \r
187     Matrix.pa12 = &a21;\r
188     Matrix.pa22 = &a22;\r
189     Matrix.pa32 = &a32;\r
190     Matrix.pa13 = &b21;\r
191     Matrix.pa23 = &b22;\r
192     Matrix.pa33 = &b23;\r
193     ComputeMatrix33(&c2, &Matrix);\r
194 \r
195 #if 1\r
196     {\r
197         LARGENUM    halfDelta;\r
198         //\r
199         // Take care of possible truncation error in later mapping operations\r
200         //\r
201         if(IsLargeNumNegative(&delta)){\r
202             LargeNumDivInt32(&delta, -2, &halfDelta);\r
203         } else {\r
204             LargeNumDivInt32(&delta, 2, &halfDelta);\r
205         }\r
206         LargeNumAdd(&c1, &halfDelta, &c1);\r
207         LargeNumAdd(&c2, &halfDelta, &c2);\r
208     }\r
209 #endif\r
210 \r
211     //\r
212     // All the numbers are determined now.\r
213     // Let's scale them back to 32 bit world\r
214     //\r
215     minShift = 0;\r
216     cShift = LargeNumBits(&a1) - MAX_COEFF_PRECISION;\r
217     if(cShift > minShift){\r
218         minShift = cShift;\r
219     }\r
220     cShift = LargeNumBits(&b1) - MAX_COEFF_PRECISION;\r
221     if(cShift > minShift){\r
222         minShift = cShift;\r
223     }\r
224     cShift = LargeNumBits(&a2) - MAX_COEFF_PRECISION;\r
225     if(cShift > minShift){\r
226         minShift = cShift;\r
227     }\r
228     cShift = LargeNumBits(&b2) - MAX_COEFF_PRECISION;\r
229     if(cShift > minShift){\r
230         minShift = cShift;\r
231     }\r
232     cShift = LargeNumBits(&c1) - MAX_TERM_PRECISION;\r
233     if(cShift > minShift){\r
234         minShift = cShift;\r
235     }\r
236     cShift = LargeNumBits(&c2) - MAX_TERM_PRECISION;\r
237     if(cShift > minShift){\r
238         minShift = cShift;\r
239     }\r
240     cShift = LargeNumBits(&delta) - 31;\r
241     if(cShift > minShift){\r
242         minShift = cShift;\r
243     }\r
244 \r
245     //\r
246     // Now, shift count is determined, shift all the numbers\r
247     //  right to obtain the 32-bit signed values\r
248     //\r
249     if(minShift){\r
250         LargeNumRAShift(&a1, minShift);\r
251         LargeNumRAShift(&a2, minShift);\r
252         LargeNumRAShift(&b1, minShift);\r
253         LargeNumRAShift(&b2, minShift);\r
254         LargeNumRAShift(&c1, minShift);\r
255         LargeNumRAShift(&c2, minShift);\r
256         LargeNumRAShift(&delta, minShift);\r
257     }\r
258     v_CalcParam.a1      = a1.u.s32.u[0];\r
259     v_CalcParam.b1      = b1.u.s32.u[0];\r
260     v_CalcParam.c1      = c1.u.s32.u[0];\r
261     v_CalcParam.a2      = a2.u.s32.u[0];\r
262     v_CalcParam.b2      = b2.u.s32.u[0];\r
263     v_CalcParam.c2      = c2.u.s32.u[0];\r
264     v_CalcParam.delta   = delta.u.s32.u[0];\r
265 \r
266      // Don't allow delta to be zero, since it gets used as a divisor\r
267     if( ! v_CalcParam.delta )\r
268     {\r
269         //RETAILMSG(1,(__TEXT("TouchPanelSetCalibration: delta of 0 invalid\r\n")));\r
270         //RETAILMSG(1,(__TEXT("\tCalibration failed.\r\n")));\r
271         v_CalcParam.delta = 1;  // any non-zero value to prevents DivByZero traps later\r
272         v_Calibrated = 0;\r
273     }\r
274     else\r
275         v_Calibrated = 1;\r
276 \r
277     return ErrorAnalysis(\r
278                     cCalibrationPoints,\r
279                     pScreenXBuffer,\r
280                     pScreenYBuffer,\r
281                     pUncalXBuffer,\r
282                     pUncalYBuffer\r
283                 );\r
284 }\r
285 \r
286 void\r
287 ComputeMatrix33(\r
288     PLARGENUM   pResult,\r
289     PMATRIX33   pMatrix\r
290     )\r
291 {\r
292     LARGENUM    lnTemp;\r
293 \r
294     LargeNumMult(pMatrix->pa11, pMatrix->pa22, &lnTemp);\r
295     LargeNumMult(pMatrix->pa33, &lnTemp, pResult);\r
296     LargeNumMult(pMatrix->pa21, pMatrix->pa32, &lnTemp);\r
297     LargeNumMult(pMatrix->pa13, &lnTemp, &lnTemp);\r
298     LargeNumAdd(pResult, &lnTemp, pResult);\r
299     LargeNumMult(pMatrix->pa12, pMatrix->pa23, &lnTemp);\r
300     LargeNumMult(pMatrix->pa31, &lnTemp, &lnTemp);\r
301     LargeNumAdd(pResult, &lnTemp, pResult);\r
302     LargeNumMult(pMatrix->pa13, pMatrix->pa22, &lnTemp);\r
303     LargeNumMult(pMatrix->pa31, &lnTemp, &lnTemp);\r
304     LargeNumSub(pResult, &lnTemp, pResult);\r
305     LargeNumMult(pMatrix->pa12, pMatrix->pa21, &lnTemp);\r
306     LargeNumMult(pMatrix->pa33, &lnTemp, &lnTemp);\r
307     LargeNumSub(pResult, &lnTemp, pResult);\r
308     LargeNumMult(pMatrix->pa23, pMatrix->pa32, &lnTemp);\r
309     LargeNumMult(pMatrix->pa11, &lnTemp, &lnTemp);\r
310     LargeNumSub(pResult, &lnTemp, pResult);\r
311 }\r
312 \r
313 void\r
314 TouchPanelCalibrateAPoint(\r
315     int   UncalX,     //@PARM The uncalibrated X coordinate\r
316     int   UncalY,     //@PARM The uncalibrated Y coordinate\r
317     int   *pCalX,     //@PARM The calibrated X coordinate\r
318     int   *pCalY      //@PARM The calibrated Y coordinate\r
319     )\r
320 {\r
321     int   x, y;\r
322 \r
323     if ( !v_Calibrated )\r
324     {\r
325         *pCalX = 200; //UncalX;\r
326         *pCalY = 160; //UncalY;\r
327         return;\r
328     }\r
329      //\r
330      // Note the *4 in the expression below.  This is a workaround\r
331      // on behalf of gwe.  It provides a form of\r
332      // sub-pixel accuracy desirable for inking\r
333      //\r
334     x = (v_CalcParam.a1 * UncalX + v_CalcParam.b1 * UncalY +\r
335          v_CalcParam.c1) * 4 / v_CalcParam.delta;\r
336     y = (v_CalcParam.a2 * UncalX + v_CalcParam.b2 * UncalY +\r
337          v_CalcParam.c2) * 4 / v_CalcParam.delta;\r
338     if ( x < 0 ){\r
339         x = 0;\r
340     }\r
341 \r
342     if ( y < 0 ){\r
343         y = 0;\r
344     }\r
345 \r
346     *pCalX = x;\r
347     *pCalY = y;\r
348 }\r
349 \r
350 unsigned char\r
351 ErrorAnalysis(\r
352     int   cCalibrationPoints,     //@PARM The number of calibration points\r
353     int   *pScreenXBuffer,        //@PARM List of screen X coords displayed\r
354     int   *pScreenYBuffer,        //@PARM List of screen Y coords displayed\r
355     int   *pUncalXBuffer,         //@PARM List of X coords collected\r
356     int   *pUncalYBuffer          //@PARM List of Y coords collected\r
357     )\r
358 {\r
359     int     i;\r
360     unsigned int  maxErr, err;\r
361     int   x,y;\r
362     int   dx,dy;\r
363     unsigned int  errThreshold = MAX_POINT_ERROR;  // Can be overridden by registry entry\r
364 #if 0\r
365     unsigned int  status, ValType, ValLen;\r
366 \r
367     //HKEY    regKey;\r
368 \r
369 \r
370     // See if there is a Maximum Calibration Error specified in the registry\r
371     //status = RegOpenKeyEx(\r
372     //                     HKEY_LOCAL_MACHINE,\r
373      //                    __TEXT("HARDWARE\\DEVICEMAP\\TOUCH"),\r
374     //                     0,\r
375     //                     0,\r
376     //                     &regKey);\r
377     if ( status == ERROR_SUCCESS ) {\r
378         ValLen = sizeof(errThreshold);\r
379         status = RegQueryValueEx(\r
380                                 regKey,\r
381                                 __TEXT("MaxCalError"),\r
382                                 NULL,\r
383                                 &ValType,\r
384                                 (PUCHAR)&errThreshold,\r
385                                 &ValLen);\r
386         // We don't care what happened.  Either we have a new value or we have the default value.\r
387         RegCloseKey(regKey);        \r
388     }\r
389 \r
390     RETAILMSG(1,(__TEXT("Maximum Allowed Error %d:\r\n"),\r
391                 errThreshold));\r
392     DEBUGMSG(1,(__TEXT("Calibration Results:\r\n")));\r
393 #endif\r
394 \r
395     maxErr = 0;\r
396     //DEBUGMSG(1,(__TEXT("   Screen    =>    Mapped\r\n")));\r
397     for(i=0; i<cCalibrationPoints; i++){\r
398         TouchPanelCalibrateAPoint(  pUncalXBuffer[i],\r
399                                     pUncalYBuffer[i],\r
400                                     &x,\r
401                                     &y\r
402                                     );\r
403         x /= 4;\r
404         y /= 4;\r
405         printk("(%4d, %4d) => (%4d, %4d)\n",\r
406         //DEBUGMSG(1,(__TEXT("(%4d, %4d) => (%4d, %4d)\r\n"),\r
407                 pScreenXBuffer[i],\r
408                 pScreenYBuffer[i],\r
409                 x,\r
410                 y\r
411                 );\r
412         dx = x - pScreenXBuffer[i];\r
413         dy = y - pScreenYBuffer[i];\r
414         err = dx * dx + dy * dy;\r
415         if(err > maxErr){\r
416             maxErr = err;\r
417         }\r
418     }\r
419     //DEBUGMSG(1,(__TEXT("Maximum error (square of Euclidean distance in screen units) = %u\r\n"),\r
420      //       maxErr\r
421     //        ));\r
422 \r
423     if (maxErr < (errThreshold * errThreshold))\r
424     {\r
425         return 1;\r
426     }\r
427     else\r
428     {\r
429         memset(&v_CalcParam, 0, sizeof(v_CalcParam));\r
430         v_Calibrated = 0;\r
431         \r
432         return 0;\r
433     }\r
434 }\r
435 \r
436 #if 0\r
437 int main(void)\r
438 {\r
439     unsigned char ret;\r
440     int cali_num = 4;\r
441     int screen_x[4], screen_y[4];\r
442     int uncali_x[4], uncali_y[4];\r
443     int tst_uncali_x, tst_uncali_y, tst_cali_x, tst_cali_y;\r
444     \r
445     screen_x[0] = 15; screen_y[0] = 15;\r
446     screen_x[1] = 15; screen_y[1] = 465;\r
447     screen_x[2] = 785; screen_y[2] = 15;\r
448     screen_x[3] = 785; screen_y[3] = 465;\r
449     \r
450     uncali_x[0] = 173; uncali_y[0] = 417;\r
451     uncali_x[1] = 148; uncali_y[1] = 3867;\r
452     uncali_x[2] = 3903; uncali_y[2] = 365;\r
453     uncali_x[3] = 3924; uncali_y[3] = 3863;\r
454     \r
455     ret = TouchPanelSetCalibration(4, screen_x, \r
456             screen_y, uncali_x, uncali_y);\r
457     if (ret == 1)\r
458         printf("TouchPanelSetCalibration OK.\n");\r
459     else\r
460         printf("TouchPanelSetCalibration FAIL.\n");\r
461 \r
462     tst_uncali_x = 2033;\r
463     tst_uncali_y = 2132;\r
464     \r
465     TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,\r
466                               &tst_cali_x, &tst_cali_y);\r
467     \r
468     printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,\r
469                                      tst_cali_x/4, tst_cali_y/4);\r
470     \r
471     tst_uncali_x = 170;\r
472     tst_uncali_y = 418;\r
473     \r
474     TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,\r
475                               &tst_cali_x, &tst_cali_y);\r
476     \r
477     printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,\r
478                                      tst_cali_x/4, tst_cali_y/4);\r
479 \r
480     tst_uncali_x = 500;\r
481     tst_uncali_y = 707;\r
482     \r
483     TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,\r
484                               &tst_cali_x, &tst_cali_y);\r
485     \r
486     printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,\r
487                                      tst_cali_x/4, tst_cali_y/4);\r
488 \r
489     tst_uncali_x = 3636;\r
490     tst_uncali_y = 2150;\r
491     \r
492     TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,\r
493                               &tst_cali_x, &tst_cali_y);\r
494     \r
495     printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,\r
496                                      tst_cali_x/4, tst_cali_y/4);\r
497                                                   \r
498     return 0;    \r
499 }\r
500 #endif\r
501 \r