diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c
index 4029f53c853935f345935ca0d6dd1b46ff4a2998..2b83b757a89ab8c9f6de46a9a37dff11992df719 100644
--- a/drivers/input/touchscreen/wm9705.c
+++ b/drivers/input/touchscreen/wm9705.c
@@ -231,6 +231,7 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
 	int current_sample = 0;
 	int valid_samples = 0;
 	int flags = 0;
+	int ret;
 
 	if (wants_pen && !wm->pen_probably_down) {
 		u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
@@ -282,7 +283,7 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
 			samples[5], samples[6], samples[7], samples[8], samples[9], *sample);
 
 		if (seco_distance_filter(wm->dev, samples, SECO_INF_SAMPLES, sample, (u16)adcsel))
-			return RC_PENUP;
+			return RC_DISCARD;
 
 		dev_dbg(wm->dev, "f(%u): %04u %04u %04u %04u %04u %04u %04u %04u %04u %04u => %04u", adcsel,
 			samples[0], samples[1], samples[2], samples[3], samples[4],
@@ -294,9 +295,30 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
 		if (wm->mach_ops && wm->mach_ops->post_sample)
 			wm->mach_ops->post_sample(adcsel);
 
-		if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) {
-			wm->pen_probably_down = 0;
-			return RC_PENUP;
+		if (wants_pen) {
+			/*
+			 * The pen-up debounce reduces the max. number of up/down
+			 * events that are forwarded.
+			 * The pen_up_debounce function checks, if the configured
+			 * debounce delay was hit and a pen-up event needs to be
+			 * triggered. Otherwise, the current samples are discarded
+			 * and the driver returns the last, valid set of samples.
+			 */
+			if (!(*sample & WM97XX_PEN_DOWN)) {
+				ret = seco_pen_up_debounce(wm->dev, wm->filter_data.pen_up_start, wm->pen_up_debounce);
+
+				if (ret < 0)
+					dev_err(wm->dev, "Error in pen-up detection");
+
+				if (ret == 0) {
+					wm->pen_probably_down = 0;
+					return RC_PENUP;
+				}
+
+				return RC_DISCARD;
+			} else {
+				wm->filter_data.pen_up_start = jiffies_to_msecs(jiffies);
+			}
 		}
 	} else {
 		wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK)
@@ -348,9 +370,12 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
 static int wm9705_poll_touch(struct wm97xx *wm, struct touch_data *data)
 {
 	int rc;
+	bool valid = true;
 
 	rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x);
-	if (rc != RC_VALID)
+	if (rc == RC_DISCARD)
+		valid = false;
+	else if (rc != RC_VALID)
 		return rc;
 
 	/*
@@ -361,20 +386,32 @@ static int wm9705_poll_touch(struct wm97xx *wm, struct touch_data *data)
 		udelay(210);
 
 	rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y);
-	if (rc != RC_VALID)
+	if (rc == RC_DISCARD)
+		valid = false;
+	else if (rc != RC_VALID)
 		return rc;
+
 	if (pil) {
 		rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, &data->p);
-		if (rc != RC_VALID)
+		if (rc == RC_DISCARD)
+			valid = false;
+		else if (rc != RC_VALID)
 			return rc;
-	} else
+	} else {
 		data->p = DEFAULT_PRESSURE;
+	}
 
-	if (wm->use_median_filter)
-		seco_median_filter(wm->dev, &wm->filter_data, data);
+	if (!valid) {
+		*data = wm->previous_data;
+	} else {
+		if (wm->use_median_filter)
+			seco_median_filter(wm->dev, &wm->filter_data, data);
+
+		if (wm->use_low_pass_filter)
+			seco_low_pass_filter(wm->dev, &wm->filter_data, data);
 
-	if (wm->use_low_pass_filter)
-		seco_low_pass_filter(wm->dev, &wm->filter_data, data);
+		wm->previous_data = *data;
+	}
 
 	return RC_VALID;
 }
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index 51be7a41cb92cabc27709bd015d71b3abb6d9e33..d0ea4935878955553dc3b4788f3988c65bea8066 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -806,6 +806,10 @@ static int wm97xx_mfd_probe(struct platform_device *pdev)
 	wm->use_infinite_mode = mfd_pdata->use_infinite_mode;
 	wm->use_median_filter = mfd_pdata->use_median_filter;
 	wm->use_low_pass_filter = mfd_pdata->use_low_pass_filter;
+	wm->pen_up_debounce = mfd_pdata->pen_up_debounce;
+
+	dev_dbg(wm->dev, "pen_up_debounce: %d",
+			wm->pen_up_debounce);
 
 	seco_init_filter(wm->dev, &wm->filter_data);
 
diff --git a/drivers/mfd/wm97xx-core.c b/drivers/mfd/wm97xx-core.c
index e5f75d968228a67943b5544e30f0bb8ad75e4bd1..bdd5da2a6c62203f4e3054d44a9fd54d11e075f0 100644
--- a/drivers/mfd/wm97xx-core.c
+++ b/drivers/mfd/wm97xx-core.c
@@ -301,6 +301,13 @@ static int wm97xx_ac97_probe(struct ac97_codec_device *adev)
 	else
 		codec_pdata->use_low_pass_filter = false;
 
+	codec_pdata->pen_up_debounce = 0;
+
+	if (of_find_property(wm97xx->dev->of_node, "wm,pen-up-debounce", NULL))
+		if(of_property_read_u32(wm97xx->dev->of_node, "wm,pen-up-debounce",
+				&codec_pdata->pen_up_debounce) != 0)
+			dev_err(wm97xx->dev, "Failed to parse integer from wm,pen-up-debounce");
+
 	switch (adev->vendor_id) {
 	case WM9705_VENDOR_ID:
 		config = &wm9705_regmap_config;
diff --git a/include/linux/mfd/wm97xx.h b/include/linux/mfd/wm97xx.h
index 98d76b72c4f78feb507d39b3fa5121c88017fcad..2c2dd9545c4af4dc80b9c4be4cec6726e06a57e4 100644
--- a/include/linux/mfd/wm97xx.h
+++ b/include/linux/mfd/wm97xx.h
@@ -20,6 +20,7 @@ struct wm97xx_platform_data {
 	bool use_infinite_mode;
 	bool use_median_filter;
 	bool use_low_pass_filter;
+	unsigned pen_up_debounce;
 };
 
 #endif
diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h
index 612bf24147744039e2f149fef90cf886e0fee4f0..fff7b22692e4c56ba71ece9c9df2a0651a5d7f50 100644
--- a/include/linux/wm97xx.h
+++ b/include/linux/wm97xx.h
@@ -164,6 +164,8 @@
    so the handler should not sleep or wait for pendown irq) */
 #define RC_PENDOWN			0x00000008
 
+#define RC_DISCARD			0x00000010
+
 /*
  * The wm97xx driver provides a private API for writing platform-specific
  * drivers.
@@ -293,7 +295,9 @@ struct wm97xx {
 	bool use_infinite_mode;
 	bool use_median_filter;
 	bool use_low_pass_filter;
+	unsigned pen_up_debounce;
 	struct seco_filter_data filter_data;
+	struct touch_data previous_data;
 };
 
 struct wm97xx_batt_pdata {