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 {