]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
tsc2301 - add coordinate average filter
authorKlaus Pedersen <klaus.k.pedersen@nokia.com>
Fri, 15 Feb 2008 21:31:39 +0000 (23:31 +0200)
committerTony Lindgren <tony@atomide.com>
Thu, 21 Feb 2008 00:20:16 +0000 (16:20 -0800)
To get good touchscreen results filtering is essential.
The filter does 2 things - it removes "bad" measurements,
and it uses average to smooth the coordinates.

Use the HW-filter in the tsc2301 to remove high frequency
noise (from backlight). Using 8 sample average is very
efficient.
Another source of noise is the screen, but that generates
low freq noise and thus require a SW filter. Using 4
coordinate history average is efficient.

Signed-off-by: Klaus Pedersen <klaus.k.pedersen@nokia.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
arch/arm/mach-omap2/board-n800.c
drivers/input/touchscreen/tsc2301_ts.c

index 542e804d33669c74a2b1c50e2fd6bc1bac4f0bc3..f161f8d18ba936280b753715b21ed79172046ef7 100644 (file)
@@ -330,7 +330,7 @@ static void __init n800_ts_set_config(void)
        if (conf != NULL) {
                if (strcmp(conf->panel_name, "lph8923") == 0) {
                        tsc2301_config.ts_x_plate_ohm   = 180;
-                       tsc2301_config.ts_hw_avg        = 4;
+                       tsc2301_config.ts_hw_avg        = 8;
                        tsc2301_config.ts_max_pressure  = 2048;
                        tsc2301_config.ts_touch_pressure = 400;
                        tsc2301_config.ts_stab_time     = 100;
@@ -341,7 +341,7 @@ static void __init n800_ts_set_config(void)
                        tsc2301_config.ts_y_fudge       = 7;
                } else if (strcmp(conf->panel_name, "ls041y3") == 0) {
                        tsc2301_config.ts_x_plate_ohm   = 280;
-                       tsc2301_config.ts_hw_avg        = 16;
+                       tsc2301_config.ts_hw_avg        = 8;
                        tsc2301_config.ts_touch_pressure = 400;
                        tsc2301_config.ts_max_pressure  = 2048;
                        tsc2301_config.ts_stab_time     = 1000;
index 148d8be02bb9b27ad7a41323fc08f3bc3bc5518a..393bba89c54daf2cd1e2bf66aa461e5a3e2d2e9c 100644 (file)
 
 #define MAX_12BIT                                      ((1 << 12) - 1)
 
+#define TS_RECT_SIZE                                   8
+#define TSF_MIN_Z1                                     100
+#define TSF_MAX_Z2                                     4000
+
+#define TSF_SAMPLES                                    4
+
+struct ts_filter {
+       int                     sample_cnt;
+
+       int                     avg_x;
+       int                     avg_y;
+       int                     avg_z1;
+       int                     avg_z2;
+};
+
 struct tsc2301_ts {
        struct input_dev        *idev;
        char                    phys[32];
@@ -110,11 +125,12 @@ struct tsc2301_ts {
        struct spi_message      read_msg;
        u16                     data[4];
 
+       struct ts_filter        filter;
+
        int                     hw_avg_max;
        u16                     x;
        u16                     y;
        u16                     p;
-       int                     sample_cnt;
 
        u16                     x_plate_ohm;
        int                     stab_time;
@@ -291,25 +307,58 @@ static void update_pen_state(struct tsc2301_ts *ts, int x, int y, int pressure)
 
 static int filter(struct tsc2301_ts *ts, int x, int y, int z1, int z2)
 {
-       int pressure, pressure_limit;
-
-       if (z1) {
-               pressure = ts->x_plate_ohm * x;
-               pressure /= 4096;
-               pressure *= z2 - z1;
-               pressure /= z1;
-       } else
-               pressure = 0;
-
-       /* If pressure value is above a preset limit (pen is barely
-        * touching the screen) we can't trust the coordinate values.
-        */
+       int inside_rect, pressure_limit, Rt;
+       struct ts_filter *tsf = &ts->filter;
+
+       /* validate pressure and position */
+       if (x > MAX_12BIT || y > MAX_12BIT)
+               return 0;
+
+       /* skip coords if the pressure-components are out of range */
+       if (z1 < TSF_MIN_Z1 || z2 > TSF_MAX_Z2)
+               return 0;
+
+       /* Use the x,y,z1,z2 directly on the first "pen down" event */
+       if (ts->event_sent) {
+               tsf->avg_x  += x;
+               tsf->avg_y  += y;
+               tsf->avg_z1 += z1;
+               tsf->avg_z2 += z2;
+
+               if (++tsf->sample_cnt < TSF_SAMPLES)
+                       return 0;
+               x = tsf->avg_x / TSF_SAMPLES;
+               y = tsf->avg_y / TSF_SAMPLES;
+               z1 = tsf->avg_z1 / TSF_SAMPLES;
+               z2 = tsf->avg_z2 / TSF_SAMPLES;
+       }
+       tsf->sample_cnt = 0;
+       tsf->avg_x  = 0;
+       tsf->avg_y  = 0;
+       tsf->avg_z1 = 0;
+       tsf->avg_z2 = 0;
+
        pressure_limit = ts->event_sent? ts->max_pressure: ts->touch_pressure;
 
-       if (pressure < pressure_limit && x < MAX_12BIT && y < MAX_12BIT) {
+       /* z1 is always at least 100: */
+       Rt = x * (z2 - z1) / z1;
+       Rt = Rt * ts->x_plate_ohm / 4096;
+       if (Rt > pressure_limit)
+               return 0;
+
+       /* discard the event if it still is within the previous rect - unless
+        * if the pressure is harder, but then use previous x,y position */
+       inside_rect = (
+           x > (int)ts->x - TS_RECT_SIZE && x < (int)ts->x + TS_RECT_SIZE &&
+           y > (int)ts->y - TS_RECT_SIZE && y < (int)ts->y + TS_RECT_SIZE);
+
+       if (!ts->event_sent || !inside_rect) {
                ts->x = x;
                ts->y = y;
-               ts->p = pressure;
+               ts->p = Rt;
+               return 1;
+       } else if (Rt < ts->p) {
+               ts->p = Rt;
                return 1;
        }
        return 0;