2 * drivers/input/touchscreen/calibration_ts.c - calibration for rk2818 spi xpt2046 device and console
\r
4 * Copyright (C) 2010 ROCKCHIP, Inc.
\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
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
15 #include <linux/kernel.h>
\r
16 #include <linux/string.h>
\r
18 #include "calibration_ts.h"
\r
19 #include "largenum_ts.h"
\r
21 #define MAX_POINT_ERROR 6
\r
24 PLARGENUM pa11, pa12, pa13;
\r
25 PLARGENUM pa21, pa22, pa23;
\r
26 PLARGENUM pa31, pa32, pa33;
\r
27 } MATRIX33, *PMATRIX33;
\r
38 CALIBRATION_PARAMETER, *PCALIBRATION_PARAMETER;
\r
40 static unsigned char v_Calibrated = 0;
\r
41 static CALIBRATION_PARAMETER v_CalcParam ={
\r
50 static CALIBRATION_PARAMETER v_CalcParam_bak = {
\r
61 int cCalibrationPoints, //@PARM The number of calibration points
\r
62 int *pScreenXBuffer, //@PARM List of screen X coords displayed
\r
63 int *pScreenYBuffer, //@PARM List of screen Y coords displayed
\r
64 int *pUncalXBuffer, //@PARM List of X coords collected
\r
65 int *pUncalYBuffer //@PARM List of Y coords collected
\r
75 TouchPanelSetCalibration(
\r
76 int cCalibrationPoints, //@PARM The number of calibration points
\r
77 int *pScreenXBuffer, //@PARM List of screen X coords displayed
\r
78 int *pScreenYBuffer, //@PARM List of screen Y coords displayed
\r
79 int *pUncalXBuffer, //@PARM List of X coords collected
\r
80 int *pUncalYBuffer //@PARM List of Y coords collected
\r
85 LARGENUM a31, a32, a33;
\r
86 LARGENUM b11, b12, b13;
\r
87 LARGENUM b21, b22, b23;
\r
94 LARGENUM a1, b1, c1;
\r
95 LARGENUM a2, b2, c2;
\r
102 //DEBUGMSG(1,(__TEXT("calibrating %d point set\r\n"), cCalibrationPoints));
\r
105 // If the calibration data is being cleared, set the flag so
\r
106 // that the conversion operation is a noop.
\r
109 if ( cCalibrationPoints == 0 )
\r
116 // Compute these large numbers
\r
118 LargeNumSet(&a11, 0);
\r
119 LargeNumSet(&a21, 0);
\r
120 LargeNumSet(&a31, 0);
\r
121 LargeNumSet(&a22, 0);
\r
122 LargeNumSet(&a32, 0);
\r
123 LargeNumSet(&a33, cCalibrationPoints);
\r
124 LargeNumSet(&b11, 0);
\r
125 LargeNumSet(&b12, 0);
\r
126 LargeNumSet(&b13, 0);
\r
127 LargeNumSet(&b21, 0);
\r
128 LargeNumSet(&b22, 0);
\r
129 LargeNumSet(&b23, 0);
\r
130 for(i=0; i<cCalibrationPoints; i++){
\r
131 LargeNumSet(&lnTouchX, pUncalXBuffer[i]);
\r
132 LargeNumSet(&lnTouchY, pUncalYBuffer[i]);
\r
133 LargeNumSet(&lnScreenX, pScreenXBuffer[i]);
\r
134 LargeNumSet(&lnScreenY, pScreenYBuffer[i]);
\r
135 LargeNumMult(&lnTouchX, &lnTouchX, &lnTemp);
\r
136 LargeNumAdd(&a11, &lnTemp, &a11);
\r
137 LargeNumMult(&lnTouchX, &lnTouchY, &lnTemp);
\r
138 LargeNumAdd(&a21, &lnTemp, &a21);
\r
139 LargeNumAdd(&a31, &lnTouchX, &a31);
\r
140 LargeNumMult(&lnTouchY, &lnTouchY, &lnTemp);
\r
141 LargeNumAdd(&a22, &lnTemp, &a22);
\r
142 LargeNumAdd(&a32, &lnTouchY, &a32);
\r
143 LargeNumMult(&lnTouchX, &lnScreenX, &lnTemp);
\r
144 LargeNumAdd(&b11, &lnTemp, &b11);
\r
145 LargeNumMult(&lnTouchY, &lnScreenX, &lnTemp);
\r
146 LargeNumAdd(&b12, &lnTemp, &b12);
\r
147 LargeNumAdd(&b13, &lnScreenX, &b13);
\r
148 LargeNumMult(&lnTouchX, &lnScreenY, &lnTemp);
\r
149 LargeNumAdd(&b21, &lnTemp, &b21);
\r
150 LargeNumMult(&lnTouchY, &lnScreenY, &lnTemp);
\r
151 LargeNumAdd(&b22, &lnTemp, &b22);
\r
152 LargeNumAdd(&b23, &lnScreenY, &b23);
\r
155 Matrix.pa11 = &a11;
\r
156 Matrix.pa21 = &a21;
\r
157 Matrix.pa31 = &a31;
\r
158 Matrix.pa12 = &a21;
\r
159 Matrix.pa22 = &a22;
\r
160 Matrix.pa32 = &a32;
\r
161 Matrix.pa13 = &a31;
\r
162 Matrix.pa23 = &a32;
\r
163 Matrix.pa33 = &a33;
\r
164 ComputeMatrix33(&delta, &Matrix);
\r
166 Matrix.pa11 = &b11;
\r
167 Matrix.pa21 = &b12;
\r
168 Matrix.pa31 = &b13;
\r
169 ComputeMatrix33(&a1, &Matrix);
\r
171 Matrix.pa11 = &a11;
\r
172 Matrix.pa21 = &a21;
\r
173 Matrix.pa31 = &a31;
\r
174 Matrix.pa12 = &b11;
\r
175 Matrix.pa22 = &b12;
\r
176 Matrix.pa32 = &b13;
\r
177 ComputeMatrix33(&b1, &Matrix);
\r
179 Matrix.pa12 = &a21;
\r
180 Matrix.pa22 = &a22;
\r
181 Matrix.pa32 = &a32;
\r
182 Matrix.pa13 = &b11;
\r
183 Matrix.pa23 = &b12;
\r
184 Matrix.pa33 = &b13;
\r
185 ComputeMatrix33(&c1, &Matrix);
\r
187 Matrix.pa13 = &a31;
\r
188 Matrix.pa23 = &a32;
\r
189 Matrix.pa33 = &a33;
\r
190 Matrix.pa11 = &b21;
\r
191 Matrix.pa21 = &b22;
\r
192 Matrix.pa31 = &b23;
\r
193 ComputeMatrix33(&a2, &Matrix);
\r
195 Matrix.pa11 = &a11;
\r
196 Matrix.pa21 = &a21;
\r
197 Matrix.pa31 = &a31;
\r
198 Matrix.pa12 = &b21;
\r
199 Matrix.pa22 = &b22;
\r
200 Matrix.pa32 = &b23;
\r
201 ComputeMatrix33(&b2, &Matrix);
\r
203 Matrix.pa12 = &a21;
\r
204 Matrix.pa22 = &a22;
\r
205 Matrix.pa32 = &a32;
\r
206 Matrix.pa13 = &b21;
\r
207 Matrix.pa23 = &b22;
\r
208 Matrix.pa33 = &b23;
\r
209 ComputeMatrix33(&c2, &Matrix);
\r
213 LARGENUM halfDelta;
\r
215 // Take care of possible truncation error in later mapping operations
\r
217 if(IsLargeNumNegative(&delta)){
\r
218 LargeNumDivInt32(&delta, -2, &halfDelta);
\r
220 LargeNumDivInt32(&delta, 2, &halfDelta);
\r
222 LargeNumAdd(&c1, &halfDelta, &c1);
\r
223 LargeNumAdd(&c2, &halfDelta, &c2);
\r
228 // All the numbers are determined now.
\r
229 // Let's scale them back to 32 bit world
\r
232 cShift = LargeNumBits(&a1) - MAX_COEFF_PRECISION;
\r
233 if(cShift > minShift){
\r
236 cShift = LargeNumBits(&b1) - MAX_COEFF_PRECISION;
\r
237 if(cShift > minShift){
\r
240 cShift = LargeNumBits(&a2) - MAX_COEFF_PRECISION;
\r
241 if(cShift > minShift){
\r
244 cShift = LargeNumBits(&b2) - MAX_COEFF_PRECISION;
\r
245 if(cShift > minShift){
\r
248 cShift = LargeNumBits(&c1) - MAX_TERM_PRECISION;
\r
249 if(cShift > minShift){
\r
252 cShift = LargeNumBits(&c2) - MAX_TERM_PRECISION;
\r
253 if(cShift > minShift){
\r
256 cShift = LargeNumBits(&delta) - 31;
\r
257 if(cShift > minShift){
\r
262 // Now, shift count is determined, shift all the numbers
\r
263 // right to obtain the 32-bit signed values
\r
266 LargeNumRAShift(&a1, minShift);
\r
267 LargeNumRAShift(&a2, minShift);
\r
268 LargeNumRAShift(&b1, minShift);
\r
269 LargeNumRAShift(&b2, minShift);
\r
270 LargeNumRAShift(&c1, minShift);
\r
271 LargeNumRAShift(&c2, minShift);
\r
272 LargeNumRAShift(&delta, minShift);
\r
274 v_CalcParam.a1 = a1.u.s32.u[0];
\r
275 v_CalcParam.b1 = b1.u.s32.u[0];
\r
276 v_CalcParam.c1 = c1.u.s32.u[0];
\r
277 v_CalcParam.a2 = a2.u.s32.u[0];
\r
278 v_CalcParam.b2 = b2.u.s32.u[0];
\r
279 v_CalcParam.c2 = c2.u.s32.u[0];
\r
280 v_CalcParam.delta = delta.u.s32.u[0];
\r
282 // Don't allow delta to be zero, since it gets used as a divisor
\r
283 if( ! v_CalcParam.delta )
\r
285 //RETAILMSG(1,(__TEXT("TouchPanelSetCalibration: delta of 0 invalid\r\n")));
\r
286 //RETAILMSG(1,(__TEXT("\tCalibration failed.\r\n")));
\r
287 v_CalcParam.delta = 1; // any non-zero value to prevents DivByZero traps later
\r
293 return ErrorAnalysis(
\r
294 cCalibrationPoints,
\r
310 LargeNumMult(pMatrix->pa11, pMatrix->pa22, &lnTemp);
\r
311 LargeNumMult(pMatrix->pa33, &lnTemp, pResult);
\r
312 LargeNumMult(pMatrix->pa21, pMatrix->pa32, &lnTemp);
\r
313 LargeNumMult(pMatrix->pa13, &lnTemp, &lnTemp);
\r
314 LargeNumAdd(pResult, &lnTemp, pResult);
\r
315 LargeNumMult(pMatrix->pa12, pMatrix->pa23, &lnTemp);
\r
316 LargeNumMult(pMatrix->pa31, &lnTemp, &lnTemp);
\r
317 LargeNumAdd(pResult, &lnTemp, pResult);
\r
318 LargeNumMult(pMatrix->pa13, pMatrix->pa22, &lnTemp);
\r
319 LargeNumMult(pMatrix->pa31, &lnTemp, &lnTemp);
\r
320 LargeNumSub(pResult, &lnTemp, pResult);
\r
321 LargeNumMult(pMatrix->pa12, pMatrix->pa21, &lnTemp);
\r
322 LargeNumMult(pMatrix->pa33, &lnTemp, &lnTemp);
\r
323 LargeNumSub(pResult, &lnTemp, pResult);
\r
324 LargeNumMult(pMatrix->pa23, pMatrix->pa32, &lnTemp);
\r
325 LargeNumMult(pMatrix->pa11, &lnTemp, &lnTemp);
\r
326 LargeNumSub(pResult, &lnTemp, pResult);
\r
330 TouchPanelCalibrateAPoint(
\r
331 int UncalX, //@PARM The uncalibrated X coordinate
\r
332 int UncalY, //@PARM The uncalibrated Y coordinate
\r
333 int *pCalX, //@PARM The calibrated X coordinate
\r
334 int *pCalY //@PARM The calibrated Y coordinate
\r
339 if ( v_Calibrated )
\r
343 // Note the *4 in the expression below. This is a workaround
\r
344 // on behalf of gwe. It provides a form of
\r
345 // sub-pixel accuracy desirable for inking
\r
347 x = (v_CalcParam.a1 * UncalX + v_CalcParam.b1 * UncalY +
\r
348 v_CalcParam.c1) * 4 / v_CalcParam.delta;
\r
349 y = (v_CalcParam.a2 * UncalX + v_CalcParam.b2 * UncalY +
\r
350 v_CalcParam.c2) * 4 / v_CalcParam.delta;
\r
353 x = (v_CalcParam_bak.a1 * UncalX + v_CalcParam_bak.b1 * UncalY +
\r
354 v_CalcParam_bak.c1) * 4 / v_CalcParam_bak.delta;
\r
355 y = (v_CalcParam_bak.a2 * UncalX + v_CalcParam_bak.b2 * UncalY +
\r
356 v_CalcParam_bak.c2) * 4 / v_CalcParam_bak.delta;
\r
372 int cCalibrationPoints, //@PARM The number of calibration points
\r
373 int *pScreenXBuffer, //@PARM List of screen X coords displayed
\r
374 int *pScreenYBuffer, //@PARM List of screen Y coords displayed
\r
375 int *pUncalXBuffer, //@PARM List of X coords collected
\r
376 int *pUncalYBuffer //@PARM List of Y coords collected
\r
380 unsigned int maxErr, err;
\r
383 unsigned int errThreshold = MAX_POINT_ERROR; // Can be overridden by registry entry
\r
385 unsigned int status, ValType, ValLen;
\r
390 // See if there is a Maximum Calibration Error specified in the registry
\r
391 //status = RegOpenKeyEx(
\r
392 // HKEY_LOCAL_MACHINE,
\r
393 // __TEXT("HARDWARE\\DEVICEMAP\\TOUCH"),
\r
397 if ( status == ERROR_SUCCESS ) {
\r
398 ValLen = sizeof(errThreshold);
\r
399 status = RegQueryValueEx(
\r
401 __TEXT("MaxCalError"),
\r
404 (PUCHAR)&errThreshold,
\r
406 // We don't care what happened. Either we have a new value or we have the default value.
\r
407 RegCloseKey(regKey);
\r
410 RETAILMSG(1,(__TEXT("Maximum Allowed Error %d:\r\n"),
\r
412 DEBUGMSG(1,(__TEXT("Calibration Results:\r\n")));
\r
416 //DEBUGMSG(1,(__TEXT(" Screen => Mapped\r\n")));
\r
417 for(i=0; i<cCalibrationPoints; i++){
\r
418 TouchPanelCalibrateAPoint( pUncalXBuffer[i],
\r
425 printk("(%4d, %4d) => (%4d, %4d)\n",
\r
426 //DEBUGMSG(1,(__TEXT("(%4d, %4d) => (%4d, %4d)\r\n"),
\r
433 dx = x - pScreenXBuffer[i];
\r
434 dy = y - pScreenYBuffer[i];
\r
435 err = dx * dx + dy * dy;
\r
440 //DEBUGMSG(1,(__TEXT("Maximum error (square of Euclidean distance in screen units) = %u\r\n"),
\r
444 if (maxErr < (errThreshold * errThreshold))
\r
446 printk(" v_CalcParam.a1=%d \n"
\r
447 "v_CalcParam.b1=%d\n"
\r
448 "v_CalcParam.c1= %d\n"
\r
449 " v_CalcParam.a2 = %d\n"
\r
450 " v_CalcParam.b2 = %d\n"
\r
451 " v_CalcParam.c2 = %d\n"
\r
452 "v_CalcParam.delta = %d\n",
\r
459 v_CalcParam.delta);
\r
464 memset(&v_CalcParam, 0, sizeof(v_CalcParam));
\r
466 v_CalcParam.a1 = v_CalcParam_bak.a1;
\r
467 v_CalcParam.b1 = v_CalcParam_bak.b1 ;
\r
468 v_CalcParam.c1= v_CalcParam_bak.c1;
\r
469 v_CalcParam.a2 = v_CalcParam_bak.a2;
\r
470 v_CalcParam.b2 = v_CalcParam_bak.b2;
\r
471 v_CalcParam.c2 = v_CalcParam_bak.c2;
\r
472 v_CalcParam.delta= v_CalcParam_bak.delta;
\r
477 #define FILTER_BUF_LEN 8
\r
483 static P sTouchFilterBuff[FILTER_BUF_LEN];
\r
484 static int sBuffIndex = 0;
\r
485 static P sReportFilter = {0,0};
\r
486 void ClearBuff(void)
\r
488 memset(sTouchFilterBuff,0,FILTER_BUF_LEN*sizeof(P));
\r
489 sReportFilter.x = 0;
\r
490 sReportFilter.y = 0;
\r
493 void addToBuff(int* x,int* y)
\r
496 index=sBuffIndex++%FILTER_BUF_LEN;
\r
497 sTouchFilterBuff[index].x = *x;
\r
498 sTouchFilterBuff[index].y = *y;
\r
500 #define TS_ERR_TDOWN -1
\r
501 #define TS_ERR_LOWBUF -2
\r
502 //#define TS_MINX 138
\r
503 //#define TS_MINY 375
\r
504 //#define TS_MAXX 3935
\r
505 //#define TS_MAXY 3920
\r
506 //#define TS_xISVALID(x) (x>=TS_MINX&&x<=TS_MAXX)
\r
507 #define TS_isINVALID(X,Y) (X==4095||Y==4095||X==0||Y==0)
\r
508 #define ABS(x) ((x)>0?(x):-(x))
\r
510 int TouchFilter(unsigned short* x,unsigned short* y,bool isdown)
\r
514 if(isdown==0&&sBuffIndex==0)
\r
521 if(!TS_isINVALID(*x,*y))
\r
523 if(sBuffIndex<FILTER_BUF_LEN)
\r
527 P *p = sTouchFilterBuff;
\r
532 if(ABS(p->x-p1->x)<60||ABS(p->y-p1->y)<60)
\r
536 //printk("p(%d,%d) p1(%d,%d)\n",p->x,p->y,p1->x,p1->y);
\r
542 if(++index>=FILTER_BUF_LEN-1)break;
\r
550 if(isdown==0&&sBuffIndex==0)
\r
555 if(!TS_isINVALID(x,y))
\r
557 if(sBuffIndex<FILTER_BUF_LEN)
\r
565 adp.x+=sTouchFilterBuff[index].x;
\r
566 adp.y+=sTouchFilterBuff[index].y;
\r
567 if(++index>=FILTER_BUF_LEN)break;
\r
569 *x = adp.x/FILTER_BUF_LEN;
\r
570 *y = adp.y/FILTER_BUF_LEN;
\r
579 void TouchReportFilter(unsigned short* x,unsigned short* y)
\r
581 if((sReportFilter.x==0&&sReportFilter.y==0)||
\r
582 (ABS(sReportFilter.x - *x)>SLAP_X&&ABS(sReportFilter.y - *y)>SLAP_Y))
\r
584 sReportFilter.x = *x;
\r
585 sReportFilter.y = *y;
\r
587 *x = sReportFilter.x;
\r
588 *y = sReportFilter.y;
\r
595 int screen_x[4], screen_y[4];
\r
596 int uncali_x[4], uncali_y[4];
\r
597 int tst_uncali_x, tst_uncali_y, tst_cali_x, tst_cali_y;
\r
599 screen_x[0] = 15; screen_y[0] = 15;
\r
600 screen_x[1] = 15; screen_y[1] = 465;
\r
601 screen_x[2] = 785; screen_y[2] = 15;
\r
602 screen_x[3] = 785; screen_y[3] = 465;
\r
604 uncali_x[0] = 173; uncali_y[0] = 417;
\r
605 uncali_x[1] = 148; uncali_y[1] = 3867;
\r
606 uncali_x[2] = 3903; uncali_y[2] = 365;
\r
607 uncali_x[3] = 3924; uncali_y[3] = 3863;
\r
609 ret = TouchPanelSetCalibration(4, screen_x,
\r
610 screen_y, uncali_x, uncali_y);
\r
612 printf("TouchPanelSetCalibration OK.\n");
\r
614 printf("TouchPanelSetCalibration FAIL.\n");
\r
616 tst_uncali_x = 2033;
\r
617 tst_uncali_y = 2132;
\r
619 TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,
\r
620 &tst_cali_x, &tst_cali_y);
\r
622 printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,
\r
623 tst_cali_x/4, tst_cali_y/4);
\r
625 tst_uncali_x = 170;
\r
626 tst_uncali_y = 418;
\r
628 TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,
\r
629 &tst_cali_x, &tst_cali_y);
\r
631 printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,
\r
632 tst_cali_x/4, tst_cali_y/4);
\r
634 tst_uncali_x = 500;
\r
635 tst_uncali_y = 707;
\r
637 TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,
\r
638 &tst_cali_x, &tst_cali_y);
\r
640 printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,
\r
641 tst_cali_x/4, tst_cali_y/4);
\r
643 tst_uncali_x = 3636;
\r
644 tst_uncali_y = 2150;
\r
646 TouchPanelCalibrateAPoint(tst_uncali_x, tst_uncali_y,
\r
647 &tst_cali_x, &tst_cali_y);
\r
649 printf("(%d, %d) >> (%d, %d)\n", tst_uncali_x, tst_uncali_y,
\r
650 tst_cali_x/4, tst_cali_y/4);
\r