#include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/sort.h>
 
 #include <linux/mfd/ti_am335x_tscadc.h>
 
        am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
 }
 
+static int titsc_cmp_coord(const void *a, const void *b)
+{
+       return *(int *)a - *(int *)b;
+}
+
 static void titsc_read_coordinates(struct titsc *ts_dev,
                u32 *x, u32 *y, u32 *z1, u32 *z2)
 {
-       unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
-       unsigned int prev_val_x = ~0, prev_val_y = ~0;
-       unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
-       unsigned int read, diff;
-       unsigned int i, channel;
+       unsigned int yvals[7], xvals[7];
+       unsigned int i, xsum = 0, ysum = 0;
        unsigned int creads = ts_dev->coordinate_readouts;
-       unsigned int first_step = TOTAL_STEPS - (creads * 2 + 2);
 
-       *z1 = *z2 = 0;
-       if (fifocount % (creads * 2 + 2))
-               fifocount -= fifocount % (creads * 2 + 2);
-       /*
-        * Delta filter is used to remove large variations in sampled
-        * values from ADC. The filter tries to predict where the next
-        * coordinate could be. This is done by taking a previous
-        * coordinate and subtracting it form current one. Further the
-        * algorithm compares the difference with that of a present value,
-        * if true the value is reported to the sub system.
-        */
-       for (i = 0; i < fifocount; i++) {
-               read = titsc_readl(ts_dev, REG_FIFO0);
-
-               channel = (read & 0xf0000) >> 16;
-               read &= 0xfff;
-               if (channel > first_step + creads + 2) {
-                       diff = abs(read - prev_val_x);
-                       if (diff < prev_diff_x) {
-                               prev_diff_x = diff;
-                               *x = read;
-                       }
-                       prev_val_x = read;
+       for (i = 0; i < creads; i++) {
+               yvals[i] = titsc_readl(ts_dev, REG_FIFO0);
+               yvals[i] &= 0xfff;
+       }
 
-               } else if (channel == first_step + creads + 1) {
-                       *z1 = read;
+       *z1 = titsc_readl(ts_dev, REG_FIFO0);
+       *z1 &= 0xfff;
+       *z2 = titsc_readl(ts_dev, REG_FIFO0);
+       *z2 &= 0xfff;
 
-               } else if (channel == first_step + creads + 2) {
-                       *z2 = read;
+       for (i = 0; i < creads; i++) {
+               xvals[i] = titsc_readl(ts_dev, REG_FIFO0);
+               xvals[i] &= 0xfff;
+       }
 
-               } else if (channel > first_step) {
-                       diff = abs(read - prev_val_y);
-                       if (diff < prev_diff_y) {
-                               prev_diff_y = diff;
-                               *y = read;
-                       }
-                       prev_val_y = read;
+       /*
+        * If co-ordinates readouts is less than 4 then
+        * report the average. In case of 4 or more
+        * readouts, sort the co-ordinate samples, drop
+        * min and max values and report the average of
+        * remaining values.
+        */
+       if (creads <=  3) {
+               for (i = 0; i < creads; i++) {
+                       ysum += yvals[i];
+                       xsum += xvals[i];
                }
+               ysum /= creads;
+               xsum /= creads;
+       } else {
+               sort(yvals, creads, sizeof(unsigned int),
+                    titsc_cmp_coord, NULL);
+               sort(xvals, creads, sizeof(unsigned int),
+                    titsc_cmp_coord, NULL);
+               for (i = 1; i < creads - 1; i++) {
+                       ysum += yvals[i];
+                       xsum += xvals[i];
+               }
+               ysum /= creads - 2;
+               xsum /= creads - 2;
        }
+       *y = ysum;
+       *x = xsum;
 }
 
 static irqreturn_t titsc_irq(int irq, void *dev)
        if (err < 0)
                return err;
 
+       if (ts_dev->coordinate_readouts <= 0) {
+               dev_warn(&pdev->dev,
+                        "invalid co-ordinate readouts, resetting it to 5\n");
+               ts_dev->coordinate_readouts = 5;
+       }
+
        err = of_property_read_u32(node, "ti,charge-delay",
                                   &ts_dev->charge_delay);
        /*