diff --git a/include/linux/input/ti_tsc.h b/include/linux/input/ti_tsc.h
index 885d869..ea0cd35 100644
--- a/include/linux/input/ti_tsc.h
+++ b/include/linux/input/ti_tsc.h
@@ -9,6 +9,8 @@ struct tsc_axis {
 	u16 min;
 	u16 max;
 	u16 inverted;
+	u16 scale;
+	s16 offset;
 };

 /**
@@ -18,7 +20,7 @@ struct tsc_axis {
  *			on the platform
  * @x:			Minimum and Maximum boundary for X axis.
  * @y:			Minimum and Maximum boundary for Y axis.
- * @x_plate_resistance:	X plate resistance.
+ * @penfilterms Timout in ms for filtering pen up events.
  * @steps_to_configure: The sequencer supports a total of
  *			16 programmable steps.
  *			A step configured to read a single
@@ -30,6 +32,6 @@ struct tsc_data {
 	int wires;
 	struct tsc_axis x;
 	struct tsc_axis y;
-	int x_plate_resistance;
+	int penfilterms;
 	int steps_to_configure;
 };


diff --git a/include/linux/mfd/ti_tscadc.h b/include/linux/mfd/ti_tscadc.h
index 6f35564..fdc8860 100644
--- a/include/linux/mfd/ti_tscadc.h
+++ b/include/linux/mfd/ti_tscadc.h
@@ -48,9 +48,11 @@

 /* IRQ enable */
 #define TSCADC_IRQENB_HW_PEN		BIT(0)
+#define TSCADC_IRQENB_EOS          BIT(1)
 #define TSCADC_IRQENB_FIFO0THRES	BIT(2)
 #define TSCADC_IRQENB_FIFO1THRES	BIT(5)
 #define TSCADC_IRQENB_PENUP		BIT(9)
+#define TSCADC_IRQENB_HW_PEN_SYNC	BIT(10)

 /* Step Configuration */
 #define TSCADC_STEPCONFIG_MODE_MASK	(3 << 0)


diff --git a/drivers/input/touchscreen/ti_tsc.c b/drivers/input/touchscreen/ti_tsc.c
index a1f8638..a567f25 100644
--- a/drivers/input/touchscreen/ti_tsc.c
+++ b/drivers/input/touchscreen/ti_tsc.c
@@ -26,12 +26,21 @@
 #include <linux/io.h>
 #include <linux/input/ti_tsc.h>
 #include <linux/delay.h>
+#include <linux/sort.h>
+#include <linux/timer.h>
 #include <linux/mfd/ti_tscadc.h>
 
 #define MAX_12BIT                       ((1 << 12) - 1)
+#define PENFILTER_DEFAULT               100  /* ms for filtering pen up events */
+
+#define TSC_MOVE_DIFF                   5   /* Report Move if diff >= n */
+#define TSC_MOVE_DIFF2 (TSC_MOVE_DIFF * TSC_MOVE_DIFF)
+#define TSC_Z_FACT                      4   /* Report Pressure Change if factor >= n */
+#define TSC_CLKDIV                      20  /* ADC Clock Divider */
+
+#define SORT_SAMPLES    16
 
 int pen = 1;
-unsigned int bckup_x = 0, bckup_y = 0;
 
 struct tscadc {
 	struct input_dev	*input;
@@ -39,17 +48,116 @@ struct tscadc {
 	int			wires;
 	struct tsc_axis		x;
 	struct tsc_axis		y;
-	int			x_plate_resistance;
+	int			penfilterjiffies;
 	int			irq;
 	int			steps_to_config;
+	struct timer_list penfiltertimer;
+	int old_sx;
+	int old_sy;
+	unsigned int old_z;
+	unsigned int x_index;
+	unsigned int y_index;
+	unsigned short x_values[SORT_SAMPLES];
+	unsigned short y_values[SORT_SAMPLES];
+
+    
 };
 
-static unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
+static ssize_t show_param(struct device *dev, struct device_attribute *attr,
+	char *buf)
+{
+	struct platform_device *pdev =  to_platform_device(dev);
+        struct tscadc *ts_dev  = (struct tscadc *) platform_get_drvdata(pdev);
+	struct tsc_axis *axis;
+	
+	if (attr->attr.name[0] == 'x') {
+		axis = &(ts_dev->x);
+	} else {
+		axis = &(ts_dev->y);
+	}
+
+	if (attr->attr.name[1] == 'i') {
+		return sprintf(buf, "%u\n", axis->inverted);
+	} else if (attr->attr.name[1] == 's') {
+		int range = axis->max - axis->min + 1;
+		return sprintf(buf, "%u (%u.%03u)\n", axis->scale, axis->scale / range,
+			(axis->scale % range) * 1000 / range);
+	} else if (attr->attr.name[1] == 'o') {
+		return sprintf(buf, "%u\n", axis->offset);
+	} else if (attr->attr.name[2] == 'a') {
+		return sprintf(buf, "%u\n", axis->max);
+	} else {
+		return sprintf(buf, "%u\n", axis->min);
+	}
+}
+
+static ssize_t store_param(struct device *dev, struct device_attribute *attr,
+	 const char *buf, size_t count)
+{
+	struct platform_device *pdev =  to_platform_device(dev);
+        struct tscadc *ts_dev  = (struct tscadc *) platform_get_drvdata(pdev);
+	struct tsc_axis *axis;
+	int val;
+
+
+	if (attr->attr.name[0] == 'x') {
+		axis = &(ts_dev->x);
+	} else {
+		axis = &(ts_dev->y);
+	}
+
+        if (sscanf(buf, "%u", &val) != 1)
+       	        return -EINVAL;
+	if (attr->attr.name[1] == 'i') {
+	        if ((val != 1) && (val != 0))
+        	        return -EINVAL;
+		axis->inverted = val;
+	} else {
+	        if ((val < 0) || (val > MAX_12BIT))
+        	        return -EINVAL;
+		if (attr->attr.name[2] == 'a') {
+			axis->max = val;
+		} else if (attr->attr.name[1] == 's') {
+			axis->scale = val;
+		} else if (attr->attr.name[1] == 'o') {
+			axis->offset = val;
+		} else {
+			axis->min = val;
+		}
+	}
+
+	if (axis == &(ts_dev->x)) {
+		input_set_abs_params(ts_dev->input, ABS_X,
+			ts_dev->x.min ? : 0,
+			ts_dev->x.max ? : MAX_12BIT,
+			0, 0);
+	} else {
+		input_set_abs_params(ts_dev->input, ABS_Y,
+			ts_dev->y.min ? : 0,
+			ts_dev->y.max ? : MAX_12BIT,
+			0, 0);
+	}
+
+        return strnlen(buf, count);
+}
+
+DEVICE_ATTR(xmin, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(ymin, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(xmax, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(ymax, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(xinvert, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(yinvert, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(xscale, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(yscale, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(xoffset, S_IRUGO | S_IWUSR, show_param, store_param);
+DEVICE_ATTR(yoffset, S_IRUGO | S_IWUSR, show_param, store_param);
+
+static inline unsigned int tscadc_readl(struct tscadc *ts, unsigned int reg)
 {
 	return readl(ts->mfd_tscadc->tscadc_base + reg);
 }
 
-static void tscadc_writel(struct tscadc *tsc, unsigned int reg,
+static inline void tscadc_writel(struct tscadc *tsc, unsigned int reg,
 					unsigned int val)
 {
 	writel(val, tsc->mfd_tscadc->tscadc_base + reg);
@@ -137,85 +245,70 @@ static void tsc_step_config(struct tscadc *ts_dev)
 	tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB_TC);
 }
 
+static void swap_samples(void *a, void *b, int size)
+{
+	unsigned short t = *(unsigned short *)a;
+	*(unsigned short *)a = *(unsigned short *)b;
+	*(unsigned short *)b = t;
+}
+
+static int comp_samples(const void *a, const void *b)
+{
+	return *(unsigned short *)a - *(unsigned short *)b;
+}
+
 static irqreturn_t tscadc_interrupt(int irq, void *dev)
 {
 	struct tscadc		*ts_dev = (struct tscadc *)dev;
 	struct input_dev	*input_dev = ts_dev->input;
 	unsigned int		status, irqclr = 0;
 	int			i;
-	int			fsm = 0, fifo0count = 0, fifo1count = 0;
-	unsigned int		readx1 = 0, ready1 = 0;
-	unsigned int		prev_val_x = ~0, prev_val_y = ~0;
-	unsigned int		prev_diff_x = ~0, prev_diff_y = ~0;
-	unsigned int		cur_diff_x = 0, cur_diff_y = 0;
-	unsigned int		val_x = 0, val_y = 0, diffx = 0, diffy = 0;
-	unsigned int		z1 = 0, z2 = 0, z = 0;
+	int			fifo0count = 0, fifo1count = 0;
+	unsigned int		readout;
+	int			val_x, val_y;
+	unsigned int		z1, z2, z;
 	unsigned int		channel;
 
 	status = tscadc_readl(ts_dev, TSCADC_REG_IRQSTATUS);
 
-	if (status & TSCADC_IRQENB_FIFO0THRES) {
+	if (status & TSCADC_IRQENB_HW_PEN_SYNC) {
+		/* Pen down event */
+		pen = 0;
+		/* Stop sending the pen up event. */
+		del_timer(&ts_dev->penfiltertimer);
+		irqclr |= TSCADC_IRQENB_HW_PEN_SYNC;
+	}
+
+	if (status & TSCADC_IRQENB_EOS) {
 		fifo0count = tscadc_readl(ts_dev, TSCADC_REG_FIFO0CNT);
 		fifo1count = tscadc_readl(ts_dev, TSCADC_REG_FIFO1CNT);
 		for (i = 0; i < (fifo0count-1); i++) {
-			readx1 = tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
-			channel = readx1 & 0xf0000;
-			channel = channel >> 0x10;
+			readout = tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
+			channel = (readout & 0xf0000) >> 0x10;
+			readout &= 0xfff;
 			if ((channel >= 0) &&
 				(channel < ts_dev->steps_to_config)) {
-				readx1 = readx1 & 0xfff;
-
 				if (ts_dev->x.inverted)
-					readx1 = ts_dev->x.max - readx1 + ts_dev->x.min;
-
-				if (readx1 > prev_val_x)
-					cur_diff_x = readx1 - prev_val_x;
-				else
-					cur_diff_x = prev_val_x - readx1;
-
-				if (cur_diff_x < prev_diff_x) {
-					prev_diff_x = cur_diff_x;
-					val_x = readx1;
-				}
-				prev_val_x = readx1;
+					readout = MAX_12BIT - readout;
+				if (ts_dev->x_index < SORT_SAMPLES)
+					ts_dev->x_values[ts_dev->x_index++] = readout;
 			}
 
-			ready1 = tscadc_readl(ts_dev, TSCADC_REG_FIFO1);
-			channel = ready1 & 0xf0000;
-			channel = channel >> 0x10;
+			readout = tscadc_readl(ts_dev, TSCADC_REG_FIFO1);
+			channel = (readout & 0xf0000) >> 0x10;
+			readout &= 0xfff;
 			if ((channel >= ts_dev->steps_to_config) &&
 				(channel < (2 * ts_dev->steps_to_config - 1))) {
-				ready1 &= 0xfff;
-
 				if (ts_dev->y.inverted)
-					ready1 = ts_dev->y.max - ready1 + ts_dev->y.min;
-
-				if (ready1 > prev_val_y)
-					cur_diff_y = ready1 - prev_val_y;
-				else
-					cur_diff_y = prev_val_y - ready1;
-
-				if (cur_diff_y < prev_diff_y) {
-					prev_diff_y = cur_diff_y;
-					val_y = ready1;
-				}
-				prev_val_y = ready1;
+					readout = MAX_12BIT - readout;
+				if (ts_dev->y_index < SORT_SAMPLES)
+					ts_dev->y_values[ts_dev->y_index++] = readout;
 			}
 		}
 
-		if (val_x > bckup_x) {
-			diffx = val_x - bckup_x;
-			diffy = val_y - bckup_y;
-		} else {
-			diffx = bckup_x - val_x;
-			diffy = bckup_y - val_y;
-		}
-		bckup_x = val_x;
-		bckup_y = val_y;
-
 		z1 = ((tscadc_readl(ts_dev, TSCADC_REG_FIFO0)) & 0xfff);
 		z2 = ((tscadc_readl(ts_dev, TSCADC_REG_FIFO1)) & 0xfff);
-
+	
 		fifo1count = tscadc_readl(ts_dev, TSCADC_REG_FIFO1CNT);
 		for (i = 0; i < fifo1count; i++)
 			tscadc_readl(ts_dev, TSCADC_REG_FIFO1);
@@ -224,68 +317,129 @@ static irqreturn_t tscadc_interrupt(int irq, void *dev)
 		for (i = 0; i < fifo0count; i++)
 			tscadc_readl(ts_dev, TSCADC_REG_FIFO0);
 
-		if ((z1 != 0) && (z2 != 0)) {
-			/*
-			 * cal pressure using formula
-			 * Resistance(touch) = x plate resistance *
-			 * x postion/4096 * ((z2 / z1) - 1)
-			 */
-			z = z2 - z1;
-			z *= val_x;
-			z *= ts_dev->x_plate_resistance;
-			z /= z1;
-			z = (z + 2047) >> 12;
-
-			/*
-			 * Sample found inconsistent by debouncing
-			 * or pressure is beyond the maximum.
-			 * Don't report it to user space.
-			 */
-			if (pen == 0) {
-				if ((diffx < 15) && (diffy < 15)
-						&& (z <= MAX_12BIT)) {
-					input_report_abs(input_dev, ABS_X,
-							val_x);
-					input_report_abs(input_dev, ABS_Y,
-							val_y);
-					input_report_abs(input_dev, ABS_PRESSURE,
-							z);
-					input_report_key(input_dev, BTN_TOUCH,
-							1);
-					input_sync(input_dev);
-				}
+		if ((z1 != 0) && (z2 != 0) && (pen == 0) && (ts_dev->x_index >= SORT_SAMPLES) && (ts_dev->y_index >= SORT_SAMPLES)) {
+			unsigned short *sp;
+			int diff_sx;
+			int diff_sy;
+			unsigned int fact_z;
+			/* sort samples */
+			sort(ts_dev->x_values, SORT_SAMPLES, sizeof(ts_dev->x_values[0]), comp_samples, swap_samples);
+			sort(ts_dev->y_values, SORT_SAMPLES, sizeof(ts_dev->y_values[0]), comp_samples, swap_samples);
+			/* calculate mean values */
+			sp = &ts_dev->x_values[(SORT_SAMPLES / 2) - 2];
+			val_x = *sp++;
+			val_x += *sp++;
+			val_x += *sp++;
+			val_x += *sp;
+			val_x >>= 2;
+			sp = &ts_dev->y_values[(SORT_SAMPLES / 2) - 2];
+			val_y = *sp++;
+			val_y += *sp++;
+			val_y += *sp++;
+			val_y += *sp;
+			val_y >>= 2;
+
+			/* z = resistance of pressure (0..MAX_12BIT) */
+			z = (z1 - z2) * (MAX_12BIT - val_x);
+			z = z / (MAX_12BIT + 1 - z1);
+			if (z > MAX_12BIT)
+				z = MAX_12BIT;
+			/* z = pressure */
+			z = MAX_12BIT - z;
+
+			/* calculate screen coordinates */
+			val_x = ((val_x - ts_dev->x.offset) * ts_dev->x.scale) >> 12;
+			val_y = ((val_y - ts_dev->y.offset) * ts_dev->y.scale) >> 12;
+		    
+			/* Check for under/overflow */
+			if (val_x < ts_dev->x.min)
+				val_x = ts_dev->x.min;
+			else if (val_x > ts_dev->x.max)
+				val_x = ts_dev->x.max;
+			if (val_y < ts_dev->y.min)
+				val_y = ts_dev->y.min;
+			else if (val_y > ts_dev->y.max)
+				val_y = ts_dev->y.max;
+            
+			/* Do not send the same coordinates twice.
+			(This will prevent CPU load in user space). */
+			diff_sx = val_x - ts_dev->old_sx;
+			if (diff_sx < 0)
+				diff_sx = -diff_sx;
+			diff_sy = val_y - ts_dev->old_sy;
+			if (diff_sy < 0)
+				diff_sy = -diff_sy;
+			
+			fact_z = TSC_Z_FACT;
+			if (z && ts_dev->old_z) {
+				if (z >= ts_dev->old_z)
+					fact_z = z / ts_dev->old_z;
+				else
+					fact_z = ts_dev->old_z / z;
+			}
+            
+			/* calculate sqr(move) */
+			diff_sx = (diff_sx * diff_sx) + (diff_sy * diff_sy);
+
+			/* Check for significant move & pressure change */
+			if ((diff_sx >= TSC_MOVE_DIFF2) || (fact_z >= TSC_Z_FACT)) {
+				ts_dev->old_sx = val_x;
+				ts_dev->old_sy = val_y;
+				ts_dev->old_z = z;
+				//printk(KERN_INFO "x=%d\n", val_x);
+				input_report_abs(input_dev, ABS_X, val_x);
+				//printk(KERN_INFO "y=%d\n", val_y);
+				input_report_abs(input_dev, ABS_Y, val_y);
+				//printk(KERN_INFO "z=%d\n", z);
+				input_report_abs(input_dev, ABS_PRESSURE, z);
+				input_report_key(input_dev, BTN_TOUCH, 1);
+				input_sync(input_dev);
 			}
+			/* Clear sample buffer */
+			ts_dev->x_index = 0;
+			ts_dev->y_index = 0;
 		}
-		irqclr |= TSCADC_IRQENB_FIFO0THRES;
+		irqclr |= TSCADC_IRQENB_EOS;
+		/* start next transfer */
+		tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB_TC);
 	}
 
-	udelay(315);
-
-	status = tscadc_readl(ts_dev, TSCADC_REG_RAWIRQSTATUS);
 	if (status & TSCADC_IRQENB_PENUP) {
 		/* Pen up event */
-		fsm = tscadc_readl(ts_dev, TSCADC_REG_ADCFSM);
-		if (fsm == 0x10) {
-			pen = 1;
-			bckup_x = 0;
-			bckup_y = 0;
-			input_report_key(input_dev, BTN_TOUCH, 0);
-			input_report_abs(input_dev, ABS_PRESSURE, 0);
-			input_sync(input_dev);
-		} else {
-			pen = 0;
-		}
+		pen = 1;
+		/* Delay pen up event to upper layers, because a small interval of
+		* pen up / pen down should not interrupt a gesture.
+		*/
+		mod_timer(&ts_dev->penfiltertimer, jiffies + ts_dev->penfilterjiffies);
 		irqclr |= TSCADC_IRQENB_PENUP;
 	}
-	irqclr |= TSCADC_IRQENB_HW_PEN;
 
 	tscadc_writel(ts_dev, TSCADC_REG_IRQSTATUS, irqclr);
 
-	tscadc_writel(ts_dev, TSCADC_REG_SE, TSCADC_STPENB_STEPENB_TC);
 	return IRQ_HANDLED;
 }
 
 /*
+ * Timer function for sending the pen up event.
+ */
+static void pentimer_timeout(unsigned long context)
+{
+    struct tscadc       *ts_dev = (struct tscadc *)context;
+    struct input_dev    *input_dev = ts_dev->input;
+
+    ts_dev->old_sx = -1000;
+    ts_dev->old_sy = -1000;
+    ts_dev->old_z = 0;
+    ts_dev->x_index = 0;
+    ts_dev->y_index = 0;
+    
+    input_report_key(input_dev, BTN_TOUCH, 0);
+    input_report_abs(input_dev, ABS_PRESSURE, 0);
+    input_sync(input_dev);
+}
+
+
+/*
 * The functions for inserting/removing driver as a module.
 */
 
@@ -331,7 +485,10 @@ static	int __devinit tscadc_probe(struct platform_device *pdev)
 	}
 
 	ts_dev->wires = pdata->tsc_init->wires;
-	ts_dev->x_plate_resistance = pdata->tsc_init->x_plate_resistance;
+	err = pdata->tsc_init->penfilterms;
+	if (!err)
+	    err = PENFILTER_DEFAULT;
+	ts_dev->penfilterjiffies = msecs_to_jiffies(err);
 	ts_dev->steps_to_config = pdata->tsc_init->steps_to_configure;
 	ts_dev->x.min = pdata->tsc_init->x.min;
 	ts_dev->x.max = pdata->tsc_init->x.max;
@@ -339,14 +496,20 @@ static	int __devinit tscadc_probe(struct platform_device *pdev)
 	ts_dev->y.min = pdata->tsc_init->y.min;
 	ts_dev->y.max = pdata->tsc_init->y.max;
 	ts_dev->y.inverted = pdata->tsc_init->y.inverted;
-
-	/* IRQ Enable */
-	irqenable = TSCADC_IRQENB_FIFO0THRES;
-	tscadc_writel(ts_dev, TSCADC_REG_IRQENABLE, irqenable);
-
+	ts_dev->x.scale = (ts_dev->x.max - ts_dev->x.min) + 1;
+	ts_dev->y.scale = (ts_dev->y.max - ts_dev->y.min) + 1;
+	init_timer(&ts_dev->penfiltertimer);
+	ts_dev->penfiltertimer.function = pentimer_timeout;
+	ts_dev->penfiltertimer.data = (unsigned long) ts_dev;
+	ts_dev->x_index = 0;
+	ts_dev->y_index = 0;
+    
+	/* Clock divider (avoid CPU load) */
+	tscadc_writel(ts_dev, TSCADC_REG_CLKDIV, TSC_CLKDIV - 1);
+    
 	tsc_step_config(ts_dev);
 
-	tscadc_writel(ts_dev, TSCADC_REG_FIFO0THR, ts_dev->steps_to_config);
+	tscadc_writel(ts_dev, TSCADC_REG_FIFO1THR, ts_dev->steps_to_config);
 
 	input_dev->name = "ti-tsc";
 	input_dev->dev.parent = &pdev->dev;
@@ -370,10 +533,77 @@ static	int __devinit tscadc_probe(struct platform_device *pdev)
 		goto err_free_irq;
 
 	platform_set_drvdata(pdev, ts_dev);
+
+        err = device_create_file(&pdev->dev, &dev_attr_xmin);
+        if (err < 0)
+                goto err_register_input;
+
+        err = device_create_file(&pdev->dev, &dev_attr_xmax);
+        if (err < 0)
+                goto err_xmin;
+
+        err = device_create_file(&pdev->dev, &dev_attr_ymin);
+        if (err < 0)
+                goto err_xmax;
+
+        err = device_create_file(&pdev->dev, &dev_attr_ymax);
+        if (err < 0)
+                goto err_ymin;
+
+        err = device_create_file(&pdev->dev, &dev_attr_xinvert);
+        if (err < 0)
+                goto err_ymax;
+
+        err = device_create_file(&pdev->dev, &dev_attr_yinvert);
+        if (err < 0)
+                goto err_xinvert;
+
+        err = device_create_file(&pdev->dev, &dev_attr_xscale);
+        if (err < 0)
+                goto err_yinvert;
+
+        err = device_create_file(&pdev->dev, &dev_attr_yscale);
+        if (err < 0)
+                goto err_xscale;
+
+        err = device_create_file(&pdev->dev, &dev_attr_xoffset);
+        if (err < 0)
+                goto err_yscale;
+
+        err = device_create_file(&pdev->dev, &dev_attr_yoffset);
+        if (err < 0)
+                goto err_xoffset;
+
+	/* IRQ Enable */
+	irqenable = TSCADC_IRQENB_EOS | TSCADC_IRQENB_PENUP | TSCADC_IRQENB_HW_PEN_SYNC;
+	tscadc_writel(ts_dev, TSCADC_REG_IRQENABLE, irqenable);
+
 	return 0;
 
+
+err_xoffset:
+	device_remove_file(&pdev->dev, &dev_attr_xoffset);
+err_yscale:
+	device_remove_file(&pdev->dev, &dev_attr_yscale);
+err_xscale:
+	device_remove_file(&pdev->dev, &dev_attr_xscale);
+err_yinvert:
+	device_remove_file(&pdev->dev, &dev_attr_yinvert);
+err_xinvert:
+	device_remove_file(&pdev->dev, &dev_attr_xinvert);
+err_ymax:
+	device_remove_file(&pdev->dev, &dev_attr_ymax);
+err_ymin:
+	device_remove_file(&pdev->dev, &dev_attr_ymin);
+err_xmax:
+	device_remove_file(&pdev->dev, &dev_attr_xmax);
+err_xmin:
+	device_remove_file(&pdev->dev, &dev_attr_xmin);
+err_register_input:
+	input_unregister_device(input_dev);
 err_free_irq:
 	free_irq(ts_dev->irq, ts_dev);
+	del_timer_sync(&ts_dev->penfiltertimer);
 err_fail:
 	input_free_device(ts_dev->input);
 err_free_mem:
@@ -388,8 +618,19 @@ static int __devexit tscadc_remove(struct platform_device *pdev)
 	struct tscadc		*ts_dev = tscadc_dev->tsc;
 
 	free_irq(ts_dev->irq, ts_dev);
+    del_timer_sync(&ts_dev->penfiltertimer);
 
 	input_unregister_device(ts_dev->input);
+	device_remove_file(&pdev->dev, &dev_attr_yoffset);
+	device_remove_file(&pdev->dev, &dev_attr_xoffset);
+	device_remove_file(&pdev->dev, &dev_attr_yscale);
+	device_remove_file(&pdev->dev, &dev_attr_xscale);
+	device_remove_file(&pdev->dev, &dev_attr_yinvert);
+	device_remove_file(&pdev->dev, &dev_attr_xinvert);
+	device_remove_file(&pdev->dev, &dev_attr_ymax);
+	device_remove_file(&pdev->dev, &dev_attr_ymin);
+	device_remove_file(&pdev->dev, &dev_attr_xmax);
+	device_remove_file(&pdev->dev, &dev_attr_xmin);
 	kfree(ts_dev);
 	platform_set_drvdata(pdev, NULL);
 
@@ -424,7 +665,7 @@ static int tsc_resume(struct platform_device *pdev)
 				TSCADC_IRQENB_HW_PEN);
 	}
 	tsc_step_config(ts_dev);
-	tscadc_writel(ts_dev, TSCADC_REG_FIFO0THR,
+	tscadc_writel(ts_dev, TSCADC_REG_FIFO1THR,
 			ts_dev->steps_to_config);
 	return 0;
 }


diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ea2c4a9..f872508 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -144,6 +144,7 @@ config TPS6507X
 
 config MFD_TI_TSCADC
 	tristate "TI ADC / Touch Screen chip support"
+	select MFD_CORE
 	help
 	  If you say yes here you get support for Texas Instruments series
 	  of Touch Screen /ADC chips.
