-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Somebody in the thread at some point said:
| Andy Green wrote:
|> I gave Nelson the patch and a pointer to a PDF from TI that explained
|> the trick and computation needed,
|
| If you still have the link, could you please post it here ?
| This sounds like something quite interesting.

http://focus.ti.com/lit/an/sbaa155a/sbaa155a.pdf

I attach the implementation, but it's against the tracking tree of a few
months ago.

- -Andy
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org

iEYEARECAAYFAkmC/w4ACgkQOjLpvpq7dMqalACbBTryG1rJR65a2jHA/zaYu9/1
bhsAn3wm7lL5LmejX8PZ8573kXZZLmif
=gW9z
-----END PGP SIGNATURE-----
test-touchscreen-pressure.patch

From: Andy Green <[email protected]>

Signed-off-by: Andy Green <[email protected]>
---

 arch/arm/mach-s3c2440/mach-gta02.c     |   20 ++-
 defconfig-gta01                        |    6 +
 defconfig-gta02                        |    7 +
 drivers/input/touchscreen/s3c2410_ts.c |  217 +++++++++++++++++++++-----------
 drivers/input/touchscreen/ts_filter.c  |   86 +++++++++++++
 include/asm-arm/arch-s3c2410/ts.h      |    4 +
 include/linux/ts_filter.h              |   27 ++++
 7 files changed, 283 insertions(+), 84 deletions(-)


diff --git a/arch/arm/mach-s3c2440/mach-gta02.c 
b/arch/arm/mach-s3c2440/mach-gta02.c
index 8c5d1cb..b033490 100644
--- a/arch/arm/mach-s3c2440/mach-gta02.c
+++ b/arch/arm/mach-s3c2440/mach-gta02.c
@@ -902,10 +902,10 @@ static struct s3c2410_udc_mach_info gta02_udc_cfg = {
 /* touchscreen configuration */
 
 static struct ts_filter_median_configuration gta02_ts_median_config = {
-       .extent = 31,
-       .decimation_below = 28,
-       .decimation_threshold = 8 * 3,
-       .decimation_above = 12,
+       .extent = 31, /* total memory of median filter */
+       .decimation_threshold = 6 * 3, /* delta that decides fast or slow */
+       .decimation_below = 28, /* slow -- accumilate lots of inp before out */
+       .decimation_above = 8, /* fast -- less inp before output so we track */
 };
 
 static struct ts_filter_mean_configuration gta02_ts_mean_config = {
@@ -915,14 +915,20 @@ static struct ts_filter_mean_configuration 
gta02_ts_mean_config = {
 
 static struct s3c2410_ts_mach_info gta02_ts_cfg = {
        .delay = 10000,
-       .presc = 0xff, /* slow as we can go */
+       /* fast as we can go to reduce time with ts plates powered */
+       .presc = 50000000 / 2500000, /* 50MHz PCLK / 2.5MHz clock needed */
+       /* only do additional area measurements every third time */
+       .area_test_ratio = 3,
+       .area_minimum = 20,
+       .area_maximum = 75,
+
        .filter_sequence = {
                [0] = &ts_filter_median_api,
-               [1] = &ts_filter_mean_api,
+//             [1] = &ts_filter_mean_api,
        },
        .filter_config = {
                [0] = &gta02_ts_median_config,
-               [1] = &gta02_ts_mean_config,
+//             [1] = &gta02_ts_mean_config,
        },
 };
 
diff --git a/defconfig-gta01 b/defconfig-gta01
index 57a7d51..08fce0c 100644
--- a/defconfig-gta01
+++ b/defconfig-gta01
@@ -159,7 +159,7 @@ CONFIG_CPU_LLSERIAL_S3C2440=y
 #
 # Power management
 #
-# CONFIG_S3C2410_PM_DEBUG is not set
+CONFIG_S3C2410_PM_DEBUG=y
 # CONFIG_S3C2410_PM_CHECK is not set
 CONFIG_S3C_LOWLEVEL_UART_PORT=0
 
@@ -1696,7 +1696,9 @@ CONFIG_FORCED_INLINING=y
 # CONFIG_SAMPLES is not set
 # CONFIG_DEBUG_USER is not set
 CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+CONFIG_DEBUG_S3C_PORT=y
 CONFIG_DEBUG_S3C_UART=0
 
 #
diff --git a/defconfig-gta02 b/defconfig-gta02
index 8150615..8ca3f9c 100644
--- a/defconfig-gta02
+++ b/defconfig-gta02
@@ -159,6 +159,7 @@ CONFIG_CPU_LLSERIAL_S3C2440=y
 #
 # Power management
 #
+CONFIG_S3C2410_PM_DEBUG=y
 # CONFIG_S3C2410_PM_CHECK is not set
 CONFIG_S3C_LOWLEVEL_UART_PORT=2
 
@@ -1020,7 +1021,7 @@ CONFIG_SPI_S3C24XX_GPIO=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_POWER_SUPPLY_DEBUG is not set
 # CONFIG_PDA_POWER is not set
-CONFIG_APM_POWER=y
+# CONFIG_APM_POWER is not set
 # CONFIG_BATTERY_DS2760 is not set
 CONFIG_BATTERY_BQ27000_HDQ=y
 CONFIG_GTA02_HDQ=y
@@ -1695,7 +1696,9 @@ CONFIG_FORCED_INLINING=y
 # CONFIG_SAMPLES is not set
 # CONFIG_DEBUG_USER is not set
 CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_LL is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+CONFIG_DEBUG_S3C_PORT=y
 CONFIG_DEBUG_S3C_UART=2
 
 #
diff --git a/drivers/input/touchscreen/s3c2410_ts.c 
b/drivers/input/touchscreen/s3c2410_ts.c
index 3b063bb..77d3f63 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -79,6 +79,18 @@
                      S3C2410_ADCTSC_AUTO_PST | \
                      S3C2410_ADCTSC_XY_PST(0))
 
+#define READZ1      (S3C2410_ADCTSC_XM_SEN | /* X- on */ \
+                     S3C2410_ADCTSC_YP_SEN | /* Y+ off -- sample this*/ \
+                     S3C2410_ADCTSC_XY_PST(0)) /* Y- off, X+ on */
+
+#define READZ2      (S3C2410_ADCTSC_XM_SEN | /* X- on */ \
+                     S3C2410_ADCTSC_XP_SEN | /* X+ off -- z1*/ \
+                     S3C2410_ADCTSC_XY_PST(0)) /* Y- off -- z2, Y+ on */
+
+#define NODRIVE             (S3C2410_ADCTSC_YP_SEN | /* Y+ off */ \
+                     S3C2410_ADCTSC_XP_SEN | /* X+ off */ \
+                     S3C2410_ADCTSC_XY_PST(0)) /* Y- off, X- off */
+
 #define DEBUG_LVL    KERN_DEBUG
 
 MODULE_AUTHOR("Arnaud Patard <[email protected]>");
@@ -99,7 +111,11 @@ static char *s3c2410ts_name = "s3c2410 TouchScreen";
 struct s3c2410ts {
        struct input_dev *dev;
        struct ts_filter *tsf[MAX_TS_FILTER_CHAIN];
-       int coords[2]; /* just X and Y for us */
+       struct s3c2410_ts_mach_info info;
+       struct ts_filter_4node_area area;
+
+       int coords[4]; /* X, Y, Z1, Z2 */
+       int running;
 };
 
 static struct s3c2410ts ts;
@@ -108,7 +124,7 @@ static void __iomem *base_addr;
 
 
 
-static inline void s3c2410_ts_connect(void)
+static void s3c2410_ts_connect(void)
 {
        s3c2410_gpio_cfgpin(S3C2410_GPG12, S3C2410_GPG12_XMON);
        s3c2410_gpio_cfgpin(S3C2410_GPG13, S3C2410_GPG13_nXPON);
@@ -118,53 +134,62 @@ static inline void s3c2410_ts_connect(void)
 
 static void touch_timer_fire(unsigned long data)
 {
-       unsigned long data0;
-       unsigned long data1;
-       int updown;
+       int area = 0;
 
-       data0 = readl(base_addr + S3C2410_ADCDAT0);
-       data1 = readl(base_addr + S3C2410_ADCDAT1);
+       /* has he lifted the stylus? */
 
-       updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
-                                           (!(data1 & S3C2410_ADCDAT0_UPDOWN));
+       if ((readl(base_addr + S3C2410_ADCDAT0) &
+                readl(base_addr + S3C2410_ADCDAT1)) & S3C2410_ADCDAT0_UPDOWN) {
 
-       if (updown) {
+               /* he's stopped touching */
 
                if (ts.tsf[0])
-                       (ts.tsf[0]->api->scale)(ts.tsf[0], &ts.coords[0]);
+                       (ts.tsf[0]->api->clear)(ts.tsf[0]);
 
-#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
-               {
-                       struct timeval tv;
+               input_report_key(ts.dev, BTN_TOUCH, 0);
+               input_report_abs(ts.dev, ABS_PRESSURE, 0);
+               input_sync(ts.dev);
 
-                       do_gettimeofday(&tv);
-                       printk(DEBUG_LVL "T:%06d, X:%03ld, Y:%03ld\n",
-                                  (int)tv.tv_usec, ts.coords[0], ts.coords[1]);
-               }
-#endif
+               printk(KERN_INFO "up\n");
 
-               input_report_abs(ts.dev, ABS_X, ts.coords[0]);
-               input_report_abs(ts.dev, ABS_Y, ts.coords[1]);
+               ts.area.last_area = 0;
+               ts.running = 0;
 
-               input_report_key(ts.dev, BTN_TOUCH, 1);
-               input_report_abs(ts.dev, ABS_PRESSURE, 1);
-               input_sync(ts.dev);
+               writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
 
-               writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
-                                                     base_addr+S3C2410_ADCTSC);
-               writel(readl(base_addr+S3C2410_ADCCON) |
-                        S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
-       } else {
+               return;
+       }
 
-               if (ts.tsf[0])
-                       (ts.tsf[0]->api->clear)(ts.tsf[0]);
+       /* no, we are still "down" */
 
-               input_report_key(ts.dev, BTN_TOUCH, 0);
-               input_report_abs(ts.dev, ABS_PRESSURE, 0);
-               input_sync(ts.dev);
+       if (ts.tsf[0])
+               area = ts_filter_4node_compute(ts.tsf[0], &ts.area,
+                                                                &ts.coords[0]);
+       printk(KERN_INFO "%d\n", area);
+       input_report_abs(ts.dev, ABS_PRESSURE, area);
 
-               writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
+#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUG
+       {
+               struct timeval tv;
+
+               do_gettimeofday(&tv);
+               printk(DEBUG_LVL "T:%06d, X:%03ld, Y:%03ld\n",
+                               (int)tv.tv_usec, ts.coords[0], ts.coords[1]);
        }
+#endif
+
+       input_report_key(ts.dev, BTN_TOUCH, 1);
+       input_report_abs(ts.dev, ABS_X, ts.coords[0]);
+       input_report_abs(ts.dev, ABS_Y, ts.coords[1]);
+
+       input_sync(ts.dev);
+
+       /* start another ADC action */
+
+       writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
+                                               base_addr+S3C2410_ADCTSC);
+       writel(readl(base_addr+S3C2410_ADCCON) |
+                       S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
 }
 
 static struct timer_list touch_timer =
@@ -172,52 +197,88 @@ static struct timer_list touch_timer =
 
 static irqreturn_t stylus_updown(int irq, void *dev_id)
 {
-       unsigned long data0;
-       unsigned long data1;
-       int updown;
-
-       data0 = readl(base_addr+S3C2410_ADCDAT0);
-       data1 = readl(base_addr+S3C2410_ADCDAT1);
-
-       updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) &&
-                                           (!(data1 & S3C2410_ADCDAT0_UPDOWN));
-
-       /* TODO we should never get an interrupt with updown set while
-        * the timer is running, but maybe we ought to verify that the
-        * timer isn't running anyways. */
-
-       if (updown)
-               touch_timer_fire(0);
+       if (!(((readl(base_addr + S3C2410_ADCDAT0) &
+              readl(base_addr + S3C2410_ADCDAT1)) & S3C2410_ADCDAT0_UPDOWN)) &&
+                                                                 !ts.running) {
+               ts.running = 1;
+               writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
+                                                     base_addr+S3C2410_ADCTSC);
+               writel(readl(base_addr+S3C2410_ADCCON) |
+                        S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
+       }
 
        return IRQ_HANDLED;
 }
 
 static irqreturn_t stylus_action(int irq, void *dev_id)
 {
-       /* grab the ADC results */
-       ts.coords[0] = readl(base_addr + S3C2410_ADCDAT0) &
+
+       switch(ts_filter_4node_area_sequencer(&ts.area, &ts.coords[0])) {
+
+       case TSF4NS_XMXP_GETYP: /* grab the X Y normal ADC results */
+               ts.coords[0] = readl(base_addr + S3C2410_ADCDAT0) &
                                                    S3C2410_ADCDAT0_XPDATA_MASK;
-       ts.coords[1] = readl(base_addr + S3C2410_ADCDAT1) &
+               ts.coords[1] = readl(base_addr + S3C2410_ADCDAT1) &
                                                    S3C2410_ADCDAT1_YPDATA_MASK;
+               /* because we get X and Y in one step, advance sequencer
+                * past the "get the Y step" it will give us next time
+                */
+               ts_filter_4node_area_sequencer(&ts.area, &ts.coords[0]);
+
+               /* if not doing area measurement next, let's go with X Y */
+               if (ts.area.step == TSF4NS_XMXP_GETYP)
+                       break;
+
+               /* set up to get the first area reading
+                * We force power across X- and Y+, then read Y-
+                */
+               writel(S3C2410_ADCTSC_PULL_UP_DISABLE | READZ2,
+                                                   base_addr + S3C2410_ADCTSC);
+               writel((readl(base_addr + S3C2410_ADCCON) & ~(7 << 3)) |
+                       S3C2410_ADCCON_ENABLE_START | (4 << 3), /* Y- */
+                                                   base_addr + S3C2410_ADCCON);
+               return IRQ_HANDLED;
+       
+       case TSF4NS_XMYP_GETYM:
+               ts.coords[2] = readl(base_addr + S3C2410_ADCDAT0) &
+                                                   S3C2410_ADCDAT0_XPDATA_MASK;
+               /* set up to get the second area reading
+                * We force power across X- and Y+, then read X+
+                */
+               writel(S3C2410_ADCTSC_PULL_UP_DISABLE | READZ2,
+                                                   base_addr + S3C2410_ADCTSC);
+               writel((readl(base_addr + S3C2410_ADCCON) & ~(7 << 3)) |
+                       S3C2410_ADCCON_ENABLE_START | (7 << 3), /* X+ */
+                                                   base_addr + S3C2410_ADCCON);
+               return IRQ_HANDLED;
+       
+       case TSF4NS_XMYP_GETXP:
+       default:
+               ts.coords[3] = readl(base_addr + S3C2410_ADCDAT0) &
+                                                   S3C2410_ADCDAT0_XPDATA_MASK;
 
-       if (!ts.tsf[0]) /* filtering is disabled then use raw directly */
-               goto real_sample;
+               ts.area.area_coords_stash[0] = ts.coords[2];
+               ts.area.area_coords_stash[1] = ts.coords[3];
 
-       /* send it to the chain of filters */
-       if ((ts.tsf[0]->api->process)(ts.tsf[0], &ts.coords[0]))
-               goto real_sample;
+               /* kill power across plates */
+               writel(S3C2410_ADCTSC_PULL_UP_DISABLE | NODRIVE,
+                                                   base_addr + S3C2410_ADCTSC);
+               break;
+       }
 
-       /*
-        * no real sample came out of processing yet,
-        * get another raw result to feed it
-        */
-       writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
+       if (ts.tsf[0] && !(ts.tsf[0]->api->process)(ts.tsf[0], &ts.coords[0])) {
+               /*
+                * no real sample came out of processing yet,
+                * get another raw result to feed it
+                */
+               writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
                                                    base_addr + S3C2410_ADCTSC);
-       writel(readl(base_addr + S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START,
-                                                   base_addr + S3C2410_ADCCON);
-       return IRQ_HANDLED;
+               writel(readl(base_addr + S3C2410_ADCCON) |
+                      S3C2410_ADCCON_ENABLE_START, base_addr + S3C2410_ADCCON);
+
+               return IRQ_HANDLED;
+       }
 
-real_sample:
        mod_timer(&touch_timer, jiffies + 1);
        writel(WAIT4INT(1), base_addr + S3C2410_ADCTSC);
 
@@ -236,13 +297,13 @@ static int __init s3c2410ts_probe(struct platform_device 
*pdev)
        struct s3c2410_ts_mach_info *info;
        struct input_dev *input_dev;
        int ret = 0;
+       int used_coord_dimensions = ARRAY_SIZE(ts.coords);
 
        dev_info(&pdev->dev, "Starting\n");
 
        info = (struct s3c2410_ts_mach_info *)pdev->dev.platform_data;
 
-       if (!info)
-       {
+       if (!info) {
                dev_err(&pdev->dev, "Hm... too bad: no platform data for ts\n");
                return -EINVAL;
        }
@@ -303,7 +364,10 @@ static int __init s3c2410ts_probe(struct platform_device 
*pdev)
        ts.dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
        input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);
        input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);
-       input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);
+       if (info->area_maximum) /* if machine data set it up... */
+               input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 100, 0, 0);
+       else
+               used_coord_dimensions = 2; /* no area, just x and y */
 
        ts.dev->private = &ts;
        ts.dev->name = s3c2410ts_name;
@@ -312,10 +376,17 @@ static int __init s3c2410ts_probe(struct platform_device 
*pdev)
        ts.dev->id.product = 0xBEEF;
        ts.dev->id.version = S3C2410TSVERSION;
 
-       /* create the filter chain set up for the 2 coordinates we produce */
+       /* copy the info struct wholesale */
+       ts.info = *info;
+
+       ts.area.test_ratio = info->area_test_ratio;
+       ts.area.min_clip = info->area_minimum;
+       ts.area.max_clip = info->area_maximum;
+
+       /* create the filter chain set up for the 3 coordinates we produce */
        ret = ts_filter_create_chain(
                (struct ts_filter_api **)&info->filter_sequence,
-                          &info->filter_config, ts.tsf, ARRAY_SIZE(ts.coords));
+                           info->filter_config, ts.tsf, used_coord_dimensions);
        if (ret)
                dev_info(&pdev->dev, "%d filter(s) initialized\n", ret);
        else /* this is OK, just means there won't be any filtering */
diff --git a/drivers/input/touchscreen/ts_filter.c 
b/drivers/input/touchscreen/ts_filter.c
index f8b2b2f..9817766 100644
--- a/drivers/input/touchscreen/ts_filter.c
+++ b/drivers/input/touchscreen/ts_filter.c
@@ -55,3 +55,89 @@ void ts_filter_destroy_chain(struct ts_filter **list)
        }
 }
 EXPORT_SYMBOL_GPL(ts_filter_destroy_chain);
+
+enum ts_filter_4node_step
+ts_filter_4node_area_sequencer(struct ts_filter_4node_area *area, int * coords)
+{
+       enum ts_filter_4node_step step = area->step;
+
+       switch (step) {
+       case TSF4NS_XMXP_GETYP: /* normal X coord */
+               area->step = TSF4NS_YMYP_GETXP;
+               break;
+       case TSF4NS_YMYP_GETXP: /* normal Y coord */
+               area->step = TSF4NS_XMXP_GETYP; /* default to go back for X */
+               if (!area->max_clip) /* not used */
+                       break;
+               if (!area->test_counter--) {
+                       area->test_counter = area->test_ratio;
+                       area->step = TSF4NS_XMYP_GETYM; /* do z1 / z2 seq */
+                       break;
+               }
+               coords[2] = area->area_coords_stash[0];
+               coords[3] = area->area_coords_stash[1];
+               break;
+       case TSF4NS_XMYP_GETYM: /* special z1 coord for area */
+               area->step = TSF4NS_XMYP_GETXP;
+               break;
+       case TSF4NS_XMYP_GETXP: /* special z2 coord for area */
+       default:
+               area->step = TSF4NS_XMXP_GETYP; /* restart after this one */
+               break;
+       }
+
+       return step;
+}
+EXPORT_SYMBOL_GPL(ts_filter_4node_area_sequencer);
+
+int ts_filter_4node_compute(struct ts_filter *tsf,
+                               struct ts_filter_4node_area *area, int * coords)
+{
+       int n;
+
+       if (!tsf || !area)
+               return 0;
+
+       /* get filters to scale their results just before use */
+       (tsf->api->scale)(tsf, coords);
+
+       if (!area->max_clip)
+               return 0;
+
+       /* we didn't get fresh area coords this time, use last computed */
+       if (area->test_counter != area->test_ratio)
+               return area->last_area;
+
+       /* avoid divide by zero */
+       if (!coords[2]) {
+               area->last_area = 100;
+
+               return area->last_area;
+       }
+
+       n = coords[0];
+       if (!n)
+               n = 1;
+
+       /* compute area depressed */
+//     area->last_area = ((950 * coords[0]) / ((((1024 * coords[3]) / 
coords[2]) - 1024)));
+       area->last_area = ((100 * coords[3]) / coords[2]);
+
+       printk(KERN_INFO "coords[0]=%d, coords[2]=%d, coords[3]=%d, area = 
%d\n",
+                             coords[0], coords[2], coords[3], area->last_area);
+
+       /* clip the area */
+       if (area->last_area < area->min_clip)
+               area->last_area = area->min_clip;
+       if (area->last_area > area->max_clip)
+               area->last_area = area->max_clip;
+
+       /* scale it up to 1 - 100 */
+       area->last_area = 100 - ((100 * (area->last_area - area->min_clip)) /
+                       (area->max_clip - area->min_clip));
+       if (area->last_area < 1)
+               area->last_area = 1;
+
+       return area->last_area;
+}
+EXPORT_SYMBOL_GPL(ts_filter_4node_compute);
diff --git a/include/asm-arm/arch-s3c2410/ts.h 
b/include/asm-arm/arch-s3c2410/ts.h
index ffd33d2..09633f7 100644
--- a/include/asm-arm/arch-s3c2410/ts.h
+++ b/include/asm-arm/arch-s3c2410/ts.h
@@ -21,6 +21,10 @@
 struct s3c2410_ts_mach_info {
        int delay;
        int presc;
+       int area_test_ratio;
+       int area_minimum;
+       int area_maximum;
+
        /* array of pointers to filter APIs we want to use, in order
         * ends on first NULL, all NULL is OK
         */
diff --git a/include/linux/ts_filter.h b/include/linux/ts_filter.h
index 7262bba..b4a5831 100644
--- a/include/linux/ts_filter.h
+++ b/include/linux/ts_filter.h
@@ -38,6 +38,25 @@ struct ts_filter {
        int coords[MAX_TS_FILTER_COORDS];
 };
 
+enum ts_filter_4node_step {
+       TSF4NS_XMXP_GETYP,
+       TSF4NS_YMYP_GETXP,
+       TSF4NS_XMYP_GETYM,
+       TSF4NS_XMYP_GETXP,      
+};
+
+struct ts_filter_4node_area {
+       int test_ratio;
+
+       int test_counter;
+       int min_clip;
+       int max_clip;
+       int area_coords_stash[2];
+
+       enum ts_filter_4node_step step;
+       int last_area;
+};
+
 /*
  * helper to create a filter chain from array of API pointers and
  * array of config ints... leaves pointers to created filters in list
@@ -51,3 +70,11 @@ extern int ts_filter_create_chain(struct ts_filter_api 
**api, void **config,
 
 extern void ts_filter_destroy_chain(struct ts_filter **list);
 #endif
+
+/* helpers to compute pressure from 4-pin touchscreen */
+
+extern enum ts_filter_4node_step
+ts_filter_4node_area_sequencer(struct ts_filter_4node_area *area, int * 
coords);
+
+extern int ts_filter_4node_compute(struct ts_filter *tsf,
+                              struct ts_filter_4node_area *area, int * coords);

Reply via email to