Re: [PATCH 2/2] input: touchscreen: ads7846.c: Re-write sampling and filtering functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 12 Mar 2019 09:21:45 +0100
David Jander <david@xxxxxxxxxxx> wrote:

> The ads7846.c touchscreen driver has several issues that stem from bad
> overall design of the sampling- and filtering routines. This patch can
> be seen as a nearly complete re-write of the driver, trying to fix the
> various issues. Most importantly, a near 100 times reduction of CPU usage
> caused by excessive context switching due to sending many different small
> SPI transfers, instead of one single (bigger) transfer to acquire all
> measurement data. The new filtering code is a bit better, less buggy
> and hopefully a lot easier to read and maintain. A potential integer-
> overflow that could cause fake touches has been fixed as well as an issue
> that caused the driver to report a pen-release when HWMON measurements are
> taken while the screen is being touched.
> Also, the unnecessary code duplication for different chip types has been
> reduced.
> This version of the driver makes use of the 16-clock-per-conversion mode
> as described in the data-sheets. It was tested with a tsc2046 but should
> work also with all other variants.
> 
> Signed-off-by: David Jander <david@xxxxxxxxxxx>
> ---
>  .../bindings/input/touchscreen/ads7846.txt    |  32 +-
>  drivers/input/touchscreen/ads7846.c           | 862 +++++++-----------
>  include/linux/spi/ads7846.h                   |  27 +-
>  3 files changed, 370 insertions(+), 551 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/ads7846.txt b/Documentation/devicetree/bindings/input/touchscreen/ads7846.txt
> index 946f4fd0133e..ebc3614609d9 100644
> --- a/Documentation/devicetree/bindings/input/touchscreen/ads7846.txt
> +++ b/Documentation/devicetree/bindings/input/touchscreen/ads7846.txt
> @@ -35,18 +35,6 @@ Optional properties:
>  	ti,swap-xy			swap x and y axis
>  	ti,invert_x			invert x axis
>  	ti,invert_y			invert y axis
> -	ti,settle-delay-usec		Settling time of the analog signals;
> -					a function of Vcc and the capacitance
> -					on the X/Y drivers.  If set to non-zero,
> -					two samples are taken with settle_delay
> -					us apart, and the second one is used.
> -					~150 uSec with 0.01uF caps (u16).
> -	ti,penirq-recheck-delay-usecs	If set to non-zero, after samples are
> -					taken this delay is applied and penirq
> -					is rechecked, to help avoid false
> -					events.  This value is affected by the
> -					material used to build the touch layer
> -					(u16).
>  	ti,x-plate-ohms			Resistance of the X-plate,
>  					in Ohms (u16).
>  	ti,y-plate-ohms			Resistance of the Y-plate,
> @@ -58,13 +46,23 @@ Optional properties:
>  	ti,pressure-min			Minimum reported pressure value
>  					(threshold) - u16.
>  	ti,pressure-max			Maximum reported pressure value (u16).
> -	ti,debounce-max			Max number of additional readings per
> -					sample (u16).
> -	ti,debounce-tol			Tolerance used for filtering (u16).
> -	ti,debounce-rep			Additional consecutive good readings
> -					required after the first two (u16).
> +	ti,skip-samples			Skip n samples after switching plates.
> +					Maximum of 4. The delay this introduces
> +					depends on the SPI clock frequency.
> +	ti,touch-resistance-threshold	Threshold of touchresistance (in Ohms)
> +					for detecting a valid touch.
> +	ti,filter-tolerance		Maximum X/Y measurement deviation (raw)
> +					of consecutive measurements.
> +	ti,sample-period-msecs		Touchscreen sample period in ms.
> +	ti,report-period-msecs		Touch report generation period in ms.
>  	ti,pendown-gpio-debounce	Platform specific debounce time for the
>  					pendown-gpio (u32).
> +	ti,pendown-glitch-max		Maximum sample times of pendown signal
> +					glitch. If sliding over a worn touch-
> +					panel, touch-contact can be interrupted
> +					briefly. Avoid detecting a pen release
> +					signal too early by waiting this amount
> +					of samples.
>  	pendown-gpio			GPIO handle describing the pin the !PENIRQ
>  					line is connected to.
>  	wakeup-source			use any event on touchscreen as wakeup event.
> diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
> index b853e889c6ec..27b09d5d7476 100644
> --- a/drivers/input/touchscreen/ads7846.c
> +++ b/drivers/input/touchscreen/ads7846.c
> @@ -1,6 +1,9 @@
>  /*
>   * ADS7846 based touchscreen and sensor driver
>   *
> + * Re-write sampling and filtering code:
> + * Copyright (c) 2019 David Jander <david@xxxxxxxxxxx>
> + *
>   * Copyright (c) 2005 David Brownell
>   * Copyright (c) 2006 Nokia Corporation
>   * Various changes: Imre Deak <imre.deak@xxxxxxxxx>
> @@ -59,37 +62,21 @@
>   */
>  
>  #define TS_POLL_DELAY	1	/* ms delay before the first sample */
> -#define TS_POLL_PERIOD	5	/* ms delay between samples */
>  
>  /* this driver doesn't aim at the peak continuous sample rate */
>  #define	SAMPLE_BITS	(8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
>  
> -struct ts_event {
> -	/*
> -	 * For portability, we can't read 12 bit values using SPI (which
> -	 * would make the controller deliver them as native byte order u16
> -	 * with msbs zeroed).  Instead, we read them as two 8-bit values,
> -	 * *** WHICH NEED BYTESWAPPING *** and range adjustment.
> -	 */
> -	u16	x;
> -	u16	y;
> -	u16	z1, z2;
> -	bool	ignore;
> -	u8	x_buf[3];
> -	u8	y_buf[3];
> +struct ads7846_vfilter_buf {
> +	bool susp;
> +	int x;
> +	int y;
> +	int rt;
>  };
>  
> -/*
> - * We allocate this separately to avoid cache line sharing issues when
> - * driver is used with DMA-based SPI controllers (like atmel_spi) on
> - * systems where main memory is not DMA-coherent (most non-x86 boards).
> - */
> -struct ads7846_packet {
> -	u8			read_x, read_y, read_z1, read_z2, pwrdown;
> -	u16			dummy;		/* for the pwrdown read */
> -	struct ts_event		tc;
> -	/* for ads7845 with mpc5121 psc spi we use 3-byte buffers */
> -	u8			read_x_cmd[3], read_y_cmd[3], pwrdown_cmd[3];
> +struct ads7846_vfilter {
> +	int bidx;
> +	int bcnt;
> +	struct ads7846_vfilter_buf fbuf[4];
>  };
>  
>  struct ads7846 {
> @@ -115,24 +102,34 @@ struct ads7846 {
>  	bool			invert_y;
>  	bool			use_internal;
>  
> -	struct ads7846_packet	*packet;
> +	struct ads7846_vfilter  vfilter;
>  
> -	struct spi_transfer	xfer[18];
> -	struct spi_message	msg[5];
> -	int			msg_count;
> -	wait_queue_head_t	wait;
> +#define MAX_SKIP_SAMPLES 4
> +/* 4 measurements, 16 bits each, skipped samples + 2, 3 byte powerdown command */
> +#define MAX_XFER_LEN ((4 * 2 * (MAX_SKIP_SAMPLES + 2)) + 3)
>  
> -	bool			pendown;
> +	unsigned int		skip_samples;
> +	unsigned int		filter_tolerance;
> +	unsigned int		rt_threshold;
> +
> +	unsigned int		sample_period;
> +	unsigned int		report_period;
> +
> +	struct ads7846_vfilter_buf touch;
> +	bool			touch_valid;
> +
> +	/* DMA-safe buffers for SPI transfers */
> +	u8			rx_buf[MAX_XFER_LEN] ____cacheline_aligned;
> +	u8			tx_buf[MAX_XFER_LEN] ____cacheline_aligned;
>  
> -	int			read_cnt;
> -	int			read_rep;
> -	int			last_read;
> +	struct spi_transfer	xfer;
> +	struct spi_message	msg;
>  
> -	u16			debounce_max;
> -	u16			debounce_tol;
> -	u16			debounce_rep;
> +	wait_queue_head_t	wait;
>  
> -	u16			penirq_recheck_delay_usecs;
> +	bool			pendown;
> +	int			penup_count;
> +	unsigned int		pendown_glitch_max;
>  
>  	struct mutex		lock;
>  	bool			stopped;	/* P: lock */
> @@ -148,12 +145,7 @@ struct ads7846 {
>  	void			(*wait_for_sync)(void);
>  };
>  
> -/* leave chip selected when we're done, for quicker re-select? */
> -#if	0
>  #define	CS_CHANGE(xfer)	((xfer).cs_change = 1)
> -#else
> -#define	CS_CHANGE(xfer)	((xfer).cs_change = 0)
> -#endif
>  
>  /*--------------------------------------------------------------------------*/
>  
> @@ -287,28 +279,14 @@ static void ads7846_enable(struct ads7846 *ts)
>   */
>  
>  struct ser_req {
> -	u8			ref_on;
> -	u8			command;
> -	u8			ref_off;
> -	u16			scratch;
> -	struct spi_message	msg;
> -	struct spi_transfer	xfer[6];
> -	/*
> -	 * DMA (thus cache coherency maintenance) requires the
> -	 * transfer buffers to live in their own cache lines.
> -	 */
> -	__be16 sample ____cacheline_aligned;
> -};
> -
> -struct ads7845_ser_req {
> -	u8			command[3];
>  	struct spi_message	msg;
>  	struct spi_transfer	xfer[2];
>  	/*
>  	 * DMA (thus cache coherency maintenance) requires the
>  	 * transfer buffers to live in their own cache lines.
>  	 */
> -	u8 sample[3] ____cacheline_aligned;
> +	u8			tx_buf[8] ____cacheline_aligned;
> +	u8			rx_buf[5] ____cacheline_aligned;
>  };
>  
>  static int ads7846_read12_ser(struct device *dev, unsigned command)
> @@ -317,26 +295,29 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
>  	struct ads7846 *ts = dev_get_drvdata(dev);
>  	struct ser_req *req;
>  	int status;
> +	int i = 0;
> +	u8 *txb;
>  
>  	req = kzalloc(sizeof *req, GFP_KERNEL);
>  	if (!req)
>  		return -ENOMEM;
>  
>  	spi_message_init(&req->msg);
> +	txb = &req->tx_buf[0];
>  
> -	/* maybe turn on internal vREF, and let it settle */
> +	/*
> +	 * maybe turn on internal vREF, and let it settle
> +	 * note: use_internal can only be true on ads7846
> +	 */
>  	if (ts->use_internal) {
> -		req->ref_on = REF_ON;
> -		req->xfer[0].tx_buf = &req->ref_on;
> -		req->xfer[0].len = 1;
> -		spi_message_add_tail(&req->xfer[0], &req->msg);
> -
> -		req->xfer[1].rx_buf = &req->scratch;
> -		req->xfer[1].len = 2;
> +		txb[i] = REF_ON;
> +		req->xfer[0].tx_buf = &txb[i];
> +		req->xfer[0].len = 3;
> +		i += 3;
>  
>  		/* for 1uF, settle for 800 usec; no cap, 100 usec.  */
> -		req->xfer[1].delay_usecs = ts->vref_delay_usecs;
> -		spi_message_add_tail(&req->xfer[1], &req->msg);
> +		req->xfer[0].delay_usecs = ts->vref_delay_usecs;
> +		spi_message_add_tail(&req->xfer[0], &req->msg);
>  
>  		/* Enable reference voltage */
>  		command |= ADS_PD10_REF_ON;
> @@ -345,76 +326,23 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
>  	/* Enable ADC in every case */
>  	command |= ADS_PD10_ADC_ON;
>  
> -	/* take sample */
> -	req->command = (u8) command;
> -	req->xfer[2].tx_buf = &req->command;
> -	req->xfer[2].len = 1;
> -	spi_message_add_tail(&req->xfer[2], &req->msg);
> -
> -	req->xfer[3].rx_buf = &req->sample;
> -	req->xfer[3].len = 2;
> -	spi_message_add_tail(&req->xfer[3], &req->msg);
> -
> -	/* REVISIT:  take a few more samples, and compare ... */
> -
> -	/* converter in low power mode & enable PENIRQ */
> -	req->ref_off = PWRDOWN;
> -	req->xfer[4].tx_buf = &req->ref_off;
> -	req->xfer[4].len = 1;
> -	spi_message_add_tail(&req->xfer[4], &req->msg);
> -
> -	req->xfer[5].rx_buf = &req->scratch;
> -	req->xfer[5].len = 2;
> -	CS_CHANGE(req->xfer[5]);
> -	spi_message_add_tail(&req->xfer[5], &req->msg);
> +	req->xfer[1].tx_buf = &txb[i];
> +	txb[i] = command;
> +	i += 2;
> +	txb[i] = PWRDOWN;
> +	i += 3;
> +	req->xfer[1].rx_buf = &req->rx_buf[0];
> +	req->xfer[1].len = 5;
> +	CS_CHANGE(req->xfer[1]);
> +	spi_message_add_tail(&req->xfer[1], &req->msg);
>  
>  	mutex_lock(&ts->lock);
> -	ads7846_stop(ts);
>  	status = spi_sync(spi, &req->msg);
> -	ads7846_restart(ts);
>  	mutex_unlock(&ts->lock);
>  
>  	if (status == 0) {
>  		/* on-wire is a must-ignore bit, a BE12 value, then padding */
> -		status = be16_to_cpu(req->sample);
> -		status = status >> 3;
> -		status &= 0x0fff;
> -	}
> -
> -	kfree(req);
> -	return status;
> -}
> -
> -static int ads7845_read12_ser(struct device *dev, unsigned command)
> -{
> -	struct spi_device *spi = to_spi_device(dev);
> -	struct ads7846 *ts = dev_get_drvdata(dev);
> -	struct ads7845_ser_req *req;
> -	int status;
> -
> -	req = kzalloc(sizeof *req, GFP_KERNEL);
> -	if (!req)
> -		return -ENOMEM;
> -
> -	spi_message_init(&req->msg);
> -
> -	req->command[0] = (u8) command;
> -	req->xfer[0].tx_buf = req->command;
> -	req->xfer[0].rx_buf = req->sample;
> -	req->xfer[0].len = 3;
> -	spi_message_add_tail(&req->xfer[0], &req->msg);
> -
> -	mutex_lock(&ts->lock);
> -	ads7846_stop(ts);
> -	status = spi_sync(spi, &req->msg);
> -	ads7846_restart(ts);
> -	mutex_unlock(&ts->lock);
> -
> -	if (status == 0) {
> -		/* BE12 value, then padding */
> -		status = be16_to_cpu(*((u16 *)&req->sample[1]));
> -		status = status >> 3;
> -		status &= 0x0fff;
> +		status = (be16_to_cpup((__be16 *)&req->rx_buf[1]) >> 3) & 0x0fff;
>  	}
>  
>  	kfree(req);
> @@ -619,201 +547,242 @@ static void null_wait_for_sync(void)
>  {
>  }
>  
> -static int ads7846_debounce_filter(void *ads, int data_idx, int *val)
> +static void ads7846_vfilter_reset(struct ads7846 *ts)
>  {
> -	struct ads7846 *ts = ads;
> +	struct ads7846_vfilter *vf = &ts->vfilter;
>  
> -	if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
> -		/* Start over collecting consistent readings. */
> -		ts->read_rep = 0;
> -		/*
> -		 * Repeat it, if this was the first read or the read
> -		 * wasn't consistent enough.
> -		 */
> -		if (ts->read_cnt < ts->debounce_max) {
> -			ts->last_read = *val;
> -			ts->read_cnt++;
> -			return ADS7846_FILTER_REPEAT;
> -		} else {
> -			/*
> -			 * Maximum number of debouncing reached and still
> -			 * not enough number of consistent readings. Abort
> -			 * the whole sample, repeat it in the next sampling
> -			 * period.
> -			 */
> -			ts->read_cnt = 0;
> -			return ADS7846_FILTER_IGNORE;
> -		}
> -	} else {
> -		if (++ts->read_rep > ts->debounce_rep) {
> -			/*
> -			 * Got a good reading for this coordinate,
> -			 * go for the next one.
> -			 */
> -			ts->read_cnt = 0;
> -			ts->read_rep = 0;
> -			return ADS7846_FILTER_OK;
> -		} else {
> -			/* Read more values that are consistent. */
> -			ts->read_cnt++;
> -			return ADS7846_FILTER_REPEAT;
> -		}
> -	}
> +	vf->bidx = 0;
> +	vf->bcnt = 0;
>  }
>  
> -static int ads7846_no_filter(void *ads, int data_idx, int *val)
> +static inline int ads7846_calc_rt(struct ads7846 *ts, int x, int z1, int z2,
> +				  bool pd)
>  {
> -	return ADS7846_FILTER_OK;
> -}
> -
> -static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
> -{
> -	int value;
> -	struct spi_transfer *t =
> -		list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
> +	int Rt;
> +	bool validz = ((ts->model == 7846) || (ts->model == 7873));
>  
> -	if (ts->model == 7845) {
> -		value = be16_to_cpup((__be16 *)&(((char *)t->rx_buf)[1]));
> -	} else {
> +	if (!validz) {
> +		/* ads7843 and ads7845 cannot measure pressure, so we fake it */
> +		if (pd)
> +			Rt = ts->rt_threshold / 2;
> +		else
> +			Rt = ts->pressure_max;
> +	} else if (likely(x && z1) && pd) {
>  		/*
> -		 * adjust:  on-wire is a must-ignore bit, a BE12 value, then
> -		 * padding; built from two 8 bit values written msb-first.
> +		 * Compute touch pressure resistance using equation #2
> +		 * To avoid a potential integer overflow on spurious
> +		 * measurements causing a false high pressure touch, we do the
> +		 * final division by 4096 in two steps to scale-down
> +		 * intermediate results with minimal loss of precision.
> +		 * We multiply by "x_plate_resistance" first, which has a
> +		 * guaranteed lower bound higher than the first partial
> +		 * divisor (16), so no resolution of the (z2-z1) term is lost.
>  		 */
> -		value = be16_to_cpup((__be16 *)t->rx_buf);
> +		Rt = z2;
> +		Rt -= z1;
> +		Rt *= ts->x_plate_ohms;
> +		Rt = (Rt + 8) >> 4; /* Pre-shift to avoid integer overflow */
> +		Rt *= x;
> +		Rt /= z1;
> +		Rt = (Rt + 128) >> 8; /* Rest of total 12 bit shift */
> +	} else {
> +		Rt = ts->pressure_max;
>  	}
> -
> -	/* enforce ADC output is 12 bits width */
> -	return (value >> 3) & 0xfff;
> -}
> -
> -static void ads7846_update_value(struct spi_message *m, int val)
> -{
> -	struct spi_transfer *t =
> -		list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
> -
> -	*(u16 *)t->rx_buf = val;
> +	return Rt;
>  }
>  
> -static void ads7846_read_state(struct ads7846 *ts)
> +/*
> + * Touch sample filter
> + *
> + * This filter does several things:
> + * 1. Each sample is comprised of two measurements for X, Y and RT.
> + *    Those pairs of samples are first analyzed to discriminate good from
> + *    bad measurments. If they are both good, the average is taken for further
> + *    processing. Bad samples are entirely discarded and TS goes back to
> + *    detection in released state.
> + * 2. If the current sample is far away from the previous one, it is marked as
> + *    suspicious and not taken into account in this report. The next sample is
> + *    Then compared to both the suspicious sample and the one preceding it.
> + *    If the new sample is closer to the older sample, the suspicious sample is
> + *    discarded. Distance comparisions are done in manhattan distance for
> + *    reasons of simplicity.
> + * 3. Up to 4 successive samples are held in a buffer.
> + *    All samples in the buffer, except suspicious ones, are averaged and
> + *    reported.
> + *
> + * Note that due to interaction between 2 and 3, even when a sample is marked
> + * as suspicious, a new report is generated, excluding this sample, but also
> + * excluding the oldest sample from the previous report, due to buffer size,
> + * so this report is not identical to the previous one! In case of a slide
> + * movement, it will be a little further into the sliding direction, which is
> + * a good thing.
> + */
> +static void ads7846_vfilter_process(struct ads7846 *ts, int x, int y, int rt)
>  {
> -	struct ads7846_packet *packet = ts->packet;
> -	struct spi_message *m;
> -	int msg_idx = 0;
> -	int val;
> -	int action;
> -	int error;
> -
> -	while (msg_idx < ts->msg_count) {
> -
> -		ts->wait_for_sync();
> -
> -		m = &ts->msg[msg_idx];
> -		error = spi_sync(ts->spi, m);
> -		if (error) {
> -			dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
> -			packet->tc.ignore = true;
> -			return;
> +	struct ads7846_vfilter *vf = &ts->vfilter;
> +	struct ads7846_vfilter_buf *this, *prev;
> +	int dx, dy, dx2, dy2;
> +	int t, i;
> +	int ax, ay, ar;
> +
> +	prev = &vf->fbuf[(vf->bidx - 1) & 3];
> +	this = &vf->fbuf[vf->bidx];
> +	dx = abs(prev->x - x);
> +	dy = abs(prev->y - y);
> +
> +	this->susp = false;
> +	if (!prev->susp && vf->bcnt) {
> +		if ((dx > ts->filter_tolerance) || (dy > ts->filter_tolerance)) {
> +			this->susp = true;
> +			dev_vdbg(&ts->spi->dev,
> +				"marked suspect: dx: %d, dy: %d\n", dx, dy);
>  		}
> +	} else if (prev->susp && (vf->bcnt > 1)) {
> +		t = (vf->bidx - 2) & 3;
> +		dx2 = abs(x - vf->fbuf[t].x);
> +		dy2 = abs(y - vf->fbuf[t].y);
> +		if ((dx2 + dy2) < (dx + dy)) {
> +			/* Overwrite previous sample */
> +			vf->bidx = (vf->bidx - 1) & 3;
> +			this = &vf->fbuf[vf->bidx];
> +			this->susp = false;
> +			vf->bcnt--;
> +			dev_vdbg(&ts->spi->dev,
> +				"skipped over suspect: dx: %d, dy: %d, dx2: %d, dy2: %d\n",
> +				dx, dy, dx2, dy2);
> +			if ((dx2 > ts->filter_tolerance) ||
> +					(dy2 > ts->filter_tolerance)) {
> +				this->susp = true;
> +				dev_vdbg(&ts->spi->dev,
> +					"marked suspect again: dx: %d, dy: %d\n",
> +					dx2, dy2);
> +			}
> +		}
> +	}
> +	this->x = x;
> +	this->y = y;
> +	this->rt = rt;
>  
> -		/*
> -		 * Last message is power down request, no need to convert
> -		 * or filter the value.
> -		 */
> -		if (msg_idx < ts->msg_count - 1) {
> -
> -			val = ads7846_get_value(ts, m);
> -
> -			action = ts->filter(ts->filter_data, msg_idx, &val);
> -			switch (action) {
> -			case ADS7846_FILTER_REPEAT:
> -				continue;
> -
> -			case ADS7846_FILTER_IGNORE:
> -				packet->tc.ignore = true;
> -				msg_idx = ts->msg_count - 1;
> -				continue;
> +	vf->bidx = (vf->bidx + 1) & 3;
> +	if (vf->bcnt < 4)
> +		vf->bcnt++;
>  
> -			case ADS7846_FILTER_OK:
> -				ads7846_update_value(m, val);
> -				packet->tc.ignore = false;
> -				msg_idx++;
> -				break;
> +	if ((vf->bcnt - this->susp) < 2) {
> +		dev_vdbg(&ts->spi->dev, "counting: %d\n", vf->bcnt);
> +		return;
> +	}
>  
> -			default:
> -				BUG();
> -			}
> -		} else {
> -			msg_idx++;
> -		}
> +	/* Average up to 4 most recent samples (3 if this is suspect) */
> +	if (this->susp) {
> +		ax = ay = ar = 0;
> +	} else {
> +		ax = x;
> +		ay = y;
> +		ar = rt;
>  	}
> +	for (t = 0; t < (vf->bcnt - 1); t++) {
> +		i = (vf->bidx - vf->bcnt + t) & 3;
> +		ax += vf->fbuf[i].x;
> +		ay += vf->fbuf[i].y;
> +		ar += vf->fbuf[i].rt;
> +	}
> +	ax /= (vf->bcnt - this->susp);
> +	ay /= (vf->bcnt - this->susp);
> +	ar /= (vf->bcnt - this->susp);
> +
> +	ts->touch.x = ax;
> +	ts->touch.y = ay;
> +	ts->touch.rt = ar;
> +	ts->touch_valid = true;
>  }
>  
> -static void ads7846_report_state(struct ads7846 *ts)
> +static bool ads7846_read_state(struct ads7846 *ts)
>  {
> -	struct ads7846_packet *packet = ts->packet;
> -	unsigned int Rt;
> -	u16 x, y, z1, z2;
> +	int error;
> +	char *rxbuf = &ts->rx_buf[0];
> +	int x0, x1, y0, y1, z10, z11, z20, z21;
> +	int rt0, rt1;
> +	int dx, dy;
> +	int skp = ts->skip_samples;
> +	int stride = (skp + 2) * 2; /* Total samples = skip_samples + 2 */
> +	int offs;
> +	bool pd;
> +
> +	ts->wait_for_sync();
> +
> +	mutex_lock(&ts->lock);
> +	pd = get_pendown_state(ts);
> +	error = spi_sync(ts->spi, &ts->msg);
> +	mutex_unlock(&ts->lock);
> +	if (error) {
> +		dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
> +		ts->touch_valid = false;
> +		return false;
> +	}
>  
>  	/*
> -	 * ads7846_get_value() does in-place conversion (including byte swap)
> -	 * from on-the-wire format as part of debouncing to get stable
> -	 * readings.
> +	 * Extract samples from RX buffer.
> +	 * RX data starts with a dummy byte (0) and then contains the sample
> +	 * data in BE16 ordering (every 2 bytes, one sample).
> +	 * First all Y-samples (2 + skip_samples total), then the same amount
> +	 * of X-samples, then same amount of Z1 and finally Z2.
>  	 */
> -	if (ts->model == 7845) {
> -		x = *(u16 *)packet->tc.x_buf;
> -		y = *(u16 *)packet->tc.y_buf;
> -		z1 = 0;
> -		z2 = 0;
> +	offs = skp * 2 + 1;
> +	y0 = (be16_to_cpup((__be16 *)&rxbuf[offs]) >> 3) & 0x0fff;
> +	x0 = (be16_to_cpup((__be16 *)&rxbuf[offs + stride]) >> 3) & 0x0fff;
> +	z10 = (be16_to_cpup((__be16 *)&rxbuf[offs + stride * 2]) >> 3) & 0x0fff;
> +	z20 = (be16_to_cpup((__be16 *)&rxbuf[offs + stride * 3]) >> 3) & 0x0fff;
> +
> +	offs = skp * 2 + 3;
> +	y1 = (be16_to_cpup((__be16 *)&rxbuf[offs]) >> 3) & 0x0fff;
> +	x1 = (be16_to_cpup((__be16 *)&rxbuf[offs + stride]) >> 3) & 0x0fff;
> +	z11 = (be16_to_cpup((__be16 *)&rxbuf[offs + stride * 2]) >> 3) & 0x0fff;
> +	z21 = (be16_to_cpup((__be16 *)&rxbuf[offs + stride * 3]) >> 3) & 0x0fff;
> +
> +	dx = abs(x0 - x1);
> +	dy = abs(y0 - y1);
> +	rt0 = ads7846_calc_rt(ts, x0, z10, z20, pd);
> +	rt1 = ads7846_calc_rt(ts, x1, z11, z21, pd);
> +
> +	dev_vdbg(&ts->spi->dev,
> +		"x0: %d, x1: %d, y0: %d, y1: %d, z1: %d, z2: %d, rt0: %d, rt2: %d pd: %d\n",
> +			x0, x1, y0, y1, z11, z21, rt0, rt1, pd);
> +	if ((rt0 < ts->rt_threshold) && (rt1 < ts->rt_threshold) &&
> +			(dx < ts->filter_tolerance) &&
> +			(dy < ts->filter_tolerance)) {
> +		ads7846_vfilter_process(ts, (x0 + x1) / 2, (y0 + y1) / 2,
> +				(rt0 + rt1) / 2);
>  	} else {
> -		x = packet->tc.x;
> -		y = packet->tc.y;
> -		z1 = packet->tc.z1;
> -		z2 = packet->tc.z2;
> +		dev_vdbg(&ts->spi->dev, "Sample not good: dx: %d, dy: %d\n",
> +				dx, dy);
>  	}
>  
> -	/* range filtering */
> -	if (x == MAX_12BIT)
> -		x = 0;
> -
> -	if (ts->model == 7843) {
> -		Rt = ts->pressure_max / 2;
> -	} else if (ts->model == 7845) {
> -		if (get_pendown_state(ts))
> -			Rt = ts->pressure_max / 2;
> -		else
> -			Rt = 0;
> -		dev_vdbg(&ts->spi->dev, "x/y: %d/%d, PD %d\n", x, y, Rt);
> -	} else if (likely(x && z1)) {
> -		/* compute touch pressure resistance using equation #2 */
> -		Rt = z2;
> -		Rt -= z1;
> -		Rt *= x;
> -		Rt *= ts->x_plate_ohms;
> -		Rt /= z1;
> -		Rt = (Rt + 2047) >> 12;
> +	/* Pendown detection glitch filter */
> +	if (pd) {
> +		ts->penup_count = 0;
>  	} else {
> -		Rt = 0;
> +		ads7846_vfilter_reset(ts);
> +		if (ts->penup_count++ < ts->pendown_glitch_max)
> +			pd = true;
>  	}
> +	return pd;
> +}
> +
> +static int ads7846_report_state(struct ads7846 *ts)
> +{
> +	unsigned int Rt = ts->touch.rt;
> +	unsigned int x = ts->touch.x;
> +	unsigned int y = ts->touch.y;
>  
>  	/*
>  	 * Sample found inconsistent by debouncing or pressure is beyond
>  	 * the maximum. Don't report it to user space, repeat at least
>  	 * once more the measurement
>  	 */
> -	if (packet->tc.ignore || Rt > ts->pressure_max) {
> -		dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
> -			 packet->tc.ignore, Rt);
> -		return;
> -	}
> -
> -	/*
> -	 * Maybe check the pendown state before reporting. This discards
> -	 * false readings when the pen is lifted.
> -	 */
> -	if (ts->penirq_recheck_delay_usecs) {
> -		udelay(ts->penirq_recheck_delay_usecs);
> -		if (!get_pendown_state(ts))
> -			Rt = 0;
> +	if (!ts->touch_valid || Rt > ts->pressure_max) {
> +		dev_vdbg(&ts->spi->dev, "valid: %d pressure: %d\n",
> +			 ts->touch_valid, Rt);
> +		return 0;
>  	}
>  
>  	/*
> @@ -849,7 +818,10 @@ static void ads7846_report_state(struct ads7846 *ts)
>  
>  		input_sync(input);
>  		dev_vdbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
> +		return 1;
>  	}
> +	ts->touch_valid = false; /* Mark as processed */
> +	return 0;
>  }
>  
>  static irqreturn_t ads7846_hard_irq(int irq, void *handle)
> @@ -863,21 +835,31 @@ static irqreturn_t ads7846_hard_irq(int irq, void *handle)
>  static irqreturn_t ads7846_irq(int irq, void *handle)
>  {
>  	struct ads7846 *ts = handle;
> +	unsigned int rj = 0;
> +	bool pd = true;
> +	unsigned int rjperiod = msecs_to_jiffies(ts->report_period);
> +	unsigned int sjperiod = msecs_to_jiffies(ts->sample_period);

Unfortunately this is wrong. Due to a last-minute cleanup fix this slipped
through untested, these 4 lines should read:

+	unsigned long rj = jiffies;
+	bool pd = true;
+	unsigned long rjperiod = msecs_to_jiffies(ts->report_period);
+	unsigned long sjperiod = msecs_to_jiffies(ts->sample_period);

Sorry for the mistake. I will await review and comments for the rest of the
patch before re-submitting this.

>  	/* Start with a small delay before checking pendown state */
>  	msleep(TS_POLL_DELAY);
>  
> -	while (!ts->stopped && get_pendown_state(ts)) {
> +	ts->touch_valid = false;
> +	while (!ts->stopped && pd) {
>  
>  		/* pen is down, continue with the measurement */
> -		ads7846_read_state(ts);
> +		pd = ads7846_read_state(ts);
>  
> -		if (!ts->stopped)
> -			ads7846_report_state(ts);
> +		if ((!ts->stopped) && time_after(jiffies, rj)) {

And this should strictly be time_after_eq... *sigh*

> +			if (ads7846_report_state(ts))
> +				rj = jiffies + rjperiod;
> +		}
>  
> -		wait_event_timeout(ts->wait, ts->stopped,
> -				   msecs_to_jiffies(TS_POLL_PERIOD));
> +		if (ts->pendown)
> +			wait_event_timeout(ts->wait, ts->stopped, sjperiod);
> +		else
> +			wait_event_timeout(ts->wait, ts->stopped, 1);
>  	}
> +	ads7846_vfilter_reset(ts);
>  
>  	if (ts->pendown && !ts->stopped) {
>  		struct input_dev *input = ts->input;
> @@ -978,16 +960,20 @@ static int ads7846_setup_pendown(struct spi_device *spi,
>  }
>  
>  /*
> - * Set up the transfers to read touchscreen state; this assumes we
> - * use formula #2 for pressure, not #3.
> + * Setup the command buffer to read out all touchscreen measurements.
> + * All commands will be transmitted in one single SPI transfer in order to
> + * reduce scheduling overhead, making use of the 16 clocks-per-conversion
> + * timing mode of the ADS784x.
>   */
>  static void ads7846_setup_spi_msg(struct ads7846 *ts,
>  				  const struct ads7846_platform_data *pdata)
>  {
> -	struct spi_message *m = &ts->msg[0];
> -	struct spi_transfer *x = ts->xfer;
> -	struct ads7846_packet *packet = ts->packet;
>  	int vref = pdata->keep_vref_on;
> +	char *txbuf = &ts->tx_buf[0];
> +	unsigned int skp = ts->skip_samples;
> +	unsigned int stride = (skp + 2) * 2; /* total samples = skip + 2 */
> +	unsigned int i;
> +	unsigned int offs;
>  
>  	if (ts->model == 7873) {
>  		/*
> @@ -999,185 +985,48 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
>  		vref = 0;
>  	}
>  
> -	ts->msg_count = 1;
> -	spi_message_init(m);
> -	m->context = ts;
> -
> -	if (ts->model == 7845) {
> -		packet->read_y_cmd[0] = READ_Y(vref);
> -		packet->read_y_cmd[1] = 0;
> -		packet->read_y_cmd[2] = 0;
> -		x->tx_buf = &packet->read_y_cmd[0];
> -		x->rx_buf = &packet->tc.y_buf[0];
> -		x->len = 3;
> -		spi_message_add_tail(x, m);
> -	} else {
> -		/* y- still on; turn on only y+ (and ADC) */
> -		packet->read_y = READ_Y(vref);
> -		x->tx_buf = &packet->read_y;
> -		x->len = 1;
> -		spi_message_add_tail(x, m);
> -
> -		x++;
> -		x->rx_buf = &packet->tc.y;
> -		x->len = 2;
> -		spi_message_add_tail(x, m);
> -	}
> +	memset(txbuf, 0, sizeof(ts->tx_buf));
>  
>  	/*
> -	 * The first sample after switching drivers can be low quality;
> -	 * optionally discard it, using a second one after the signals
> -	 * have had enough time to stabilize.
> +	 * Fill the TX buffer with command data. The ADS874x can process 1
> +	 * command every 2 bytes. Command bytes are filled starting at
> +	 * index 0 of the TX buffer.
> +	 * Every measurement command will be repeated (2 + skip_samples) times.
> +	 * First Y measurements, then X, Z1 and finally Z2.
> +	 * The skip_samples parameter is used to insert up to 2 dummy
> +	 * measurements before the 2 real measurements. The results of these
> +	 * dummy measurements are skipped. The idea is to give the signals time
> +	 * to settle after switching the plates.
> +	 * The last 2 consecutive measurements are always used for validation
> +	 * and filtering.
>  	 */
> -	if (pdata->settle_delay_usecs) {
> -		x->delay_usecs = pdata->settle_delay_usecs;
> -
> -		x++;
> -		x->tx_buf = &packet->read_y;
> -		x->len = 1;
> -		spi_message_add_tail(x, m);
> -
> -		x++;
> -		x->rx_buf = &packet->tc.y;
> -		x->len = 2;
> -		spi_message_add_tail(x, m);
> -	}
> -
> -	ts->msg_count++;
> -	m++;
> -	spi_message_init(m);
> -	m->context = ts;
> -
> -	if (ts->model == 7845) {
> -		x++;
> -		packet->read_x_cmd[0] = READ_X(vref);
> -		packet->read_x_cmd[1] = 0;
> -		packet->read_x_cmd[2] = 0;
> -		x->tx_buf = &packet->read_x_cmd[0];
> -		x->rx_buf = &packet->tc.x_buf[0];
> -		x->len = 3;
> -		spi_message_add_tail(x, m);
> -	} else {
> -		/* turn y- off, x+ on, then leave in lowpower */
> -		x++;
> -		packet->read_x = READ_X(vref);
> -		x->tx_buf = &packet->read_x;
> -		x->len = 1;
> -		spi_message_add_tail(x, m);
> -
> -		x++;
> -		x->rx_buf = &packet->tc.x;
> -		x->len = 2;
> -		spi_message_add_tail(x, m);
> -	}
> -
> -	/* ... maybe discard first sample ... */
> -	if (pdata->settle_delay_usecs) {
> -		x->delay_usecs = pdata->settle_delay_usecs;
> -
> -		x++;
> -		x->tx_buf = &packet->read_x;
> -		x->len = 1;
> -		spi_message_add_tail(x, m);
> -
> -		x++;
> -		x->rx_buf = &packet->tc.x;
> -		x->len = 2;
> -		spi_message_add_tail(x, m);
> -	}
> -
> -	/* turn y+ off, x- on; we'll use formula #2 */
> -	if (ts->model == 7846) {
> -		ts->msg_count++;
> -		m++;
> -		spi_message_init(m);
> -		m->context = ts;
> -
> -		x++;
> -		packet->read_z1 = READ_Z1(vref);
> -		x->tx_buf = &packet->read_z1;
> -		x->len = 1;
> -		spi_message_add_tail(x, m);
> -
> -		x++;
> -		x->rx_buf = &packet->tc.z1;
> -		x->len = 2;
> -		spi_message_add_tail(x, m);
> -
> -		/* ... maybe discard first sample ... */
> -		if (pdata->settle_delay_usecs) {
> -			x->delay_usecs = pdata->settle_delay_usecs;
> -
> -			x++;
> -			x->tx_buf = &packet->read_z1;
> -			x->len = 1;
> -			spi_message_add_tail(x, m);
> -
> -			x++;
> -			x->rx_buf = &packet->tc.z1;
> -			x->len = 2;
> -			spi_message_add_tail(x, m);
> -		}
> -
> -		ts->msg_count++;
> -		m++;
> -		spi_message_init(m);
> -		m->context = ts;
> -
> -		x++;
> -		packet->read_z2 = READ_Z2(vref);
> -		x->tx_buf = &packet->read_z2;
> -		x->len = 1;
> -		spi_message_add_tail(x, m);
> -
> -		x++;
> -		x->rx_buf = &packet->tc.z2;
> -		x->len = 2;
> -		spi_message_add_tail(x, m);
> -
> -		/* ... maybe discard first sample ... */
> -		if (pdata->settle_delay_usecs) {
> -			x->delay_usecs = pdata->settle_delay_usecs;
> -
> -			x++;
> -			x->tx_buf = &packet->read_z2;
> -			x->len = 1;
> -			spi_message_add_tail(x, m);
> -
> -			x++;
> -			x->rx_buf = &packet->tc.z2;
> -			x->len = 2;
> -			spi_message_add_tail(x, m);
> +	for (i = 0; i < (skp + 2); i++) {
> +		offs = i * 2;
> +		txbuf[offs] = READ_Y(vref);
> +		txbuf[offs + stride] = READ_X(vref);
> +		if (ts->model == 7846) {
> +			txbuf[offs + stride * 2] = READ_Z1(vref);
> +			txbuf[offs + stride * 3] = READ_Z2(vref);
>  		}
>  	}
> +	if (ts->model == 7846)
> +		txbuf[stride * 4] = PWRDOWN;
> +	else
> +		txbuf[stride * 2] = PWRDOWN;
>  
> -	/* power down */
> -	ts->msg_count++;
> -	m++;
> -	spi_message_init(m);
> -	m->context = ts;
> -
> -	if (ts->model == 7845) {
> -		x++;
> -		packet->pwrdown_cmd[0] = PWRDOWN;
> -		packet->pwrdown_cmd[1] = 0;
> -		packet->pwrdown_cmd[2] = 0;
> -		x->tx_buf = &packet->pwrdown_cmd[0];
> -		x->len = 3;
> -	} else {
> -		x++;
> -		packet->pwrdown = PWRDOWN;
> -		x->tx_buf = &packet->pwrdown;
> -		x->len = 1;
> -		spi_message_add_tail(x, m);
> -
> -		x++;
> -		x->rx_buf = &packet->dummy;
> -		x->len = 2;
> -	}
> +	spi_message_init(&ts->msg);
> +	ts->msg.context = ts;
>  
> -	CS_CHANGE(*x);
> -	spi_message_add_tail(x, m);
> +	ts->xfer.rx_buf = &ts->rx_buf[0];
> +	ts->xfer.tx_buf = txbuf;
> +	if (ts->model == 7846)
> +		ts->xfer.len = stride * 4 + 3;
> +	else
> +		ts->xfer.len = stride * 2 + 3;
> +	ts->xfer.bits_per_word = 8;
> +
> +	CS_CHANGE(ts->xfer);
> +	spi_message_add_tail(&ts->xfer, &ts->msg);
>  }
>  
>  #ifdef CONFIG_OF
> @@ -1223,11 +1072,6 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
>  	pdata->invert_x = of_property_read_bool(node, "ti,invert_x");
>  	pdata->invert_y = of_property_read_bool(node, "ti,invert_y");
>  
> -	of_property_read_u16(node, "ti,settle-delay-usec",
> -			     &pdata->settle_delay_usecs);
> -	of_property_read_u16(node, "ti,penirq-recheck-delay-usecs",
> -			     &pdata->penirq_recheck_delay_usecs);
> -
>  	of_property_read_u16(node, "ti,x-plate-ohms", &pdata->x_plate_ohms);
>  	of_property_read_u16(node, "ti,y-plate-ohms", &pdata->y_plate_ohms);
>  
> @@ -1239,13 +1083,21 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev)
>  	of_property_read_u16(node, "ti,pressure-min", &pdata->pressure_min);
>  	of_property_read_u16(node, "ti,pressure-max", &pdata->pressure_max);
>  
> -	of_property_read_u16(node, "ti,debounce-max", &pdata->debounce_max);
> -	of_property_read_u16(node, "ti,debounce-tol", &pdata->debounce_tol);
> -	of_property_read_u16(node, "ti,debounce-rep", &pdata->debounce_rep);
> -
>  	of_property_read_u32(node, "ti,pendown-gpio-debounce",
>  			     &pdata->gpio_pendown_debounce);
>  
> +	of_property_read_u32(node, "ti,skip-samples", &pdata->skip_samples);
> +	of_property_read_u32(node, "ti,sample-period-msecs",
> +			     &pdata->sample_period);
> +	of_property_read_u32(node, "ti,report-period-msecs",
> +			     &pdata->report_period);
> +	of_property_read_u32(node, "ti,filter-tolerance",
> +			     &pdata->filter_tolerance);
> +	of_property_read_u32(node, "ti,touch-resistance-threshold",
> +			     &pdata->rt_threshold);
> +	of_property_read_u32(node, "ti,pendown-glitch-max",
> +			     &pdata->pendown_glitch_max);
> +
>  	pdata->wakeup = of_property_read_bool(node, "wakeup-source") ||
>  			of_property_read_bool(node, "linux,wakeup");
>  
> @@ -1265,7 +1117,6 @@ static int ads7846_probe(struct spi_device *spi)
>  {
>  	const struct ads7846_platform_data *pdata;
>  	struct ads7846 *ts;
> -	struct ads7846_packet *packet;
>  	struct input_dev *input_dev;
>  	unsigned long irq_flags;
>  	int err;
> @@ -1294,16 +1145,14 @@ static int ads7846_probe(struct spi_device *spi)
>  		return err;
>  
>  	ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
> -	packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
>  	input_dev = input_allocate_device();
> -	if (!ts || !packet || !input_dev) {
> +	if (!ts || !input_dev) {
>  		err = -ENOMEM;
>  		goto err_free_mem;
>  	}
>  
>  	spi_set_drvdata(spi, ts);
>  
> -	ts->packet = packet;
>  	ts->spi = spi;
>  	ts->input = input_dev;
>  
> @@ -1323,40 +1172,23 @@ static int ads7846_probe(struct spi_device *spi)
>  	ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
>  	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
>  	ts->pressure_max = pdata->pressure_max ? : ~0;
> +	ts->skip_samples = (pdata->skip_samples <= MAX_SKIP_SAMPLES) ?
> +		pdata->skip_samples : 0;
> +	ts->sample_period = pdata->sample_period ? : 10;
> +	ts->report_period = pdata->report_period ? : 10;
> +	ts->filter_tolerance = pdata->filter_tolerance ? : 80;
> +	ts->rt_threshold = pdata->rt_threshold ? : 3500;
> +	ts->pendown_glitch_max = pdata->pendown_glitch_max;
>  
>  	ts->vref_mv = pdata->vref_mv;
>  	ts->swap_xy = pdata->swap_xy;
>  	ts->invert_x = pdata->invert_x;
>  	ts->invert_y = pdata->invert_y;
>  
> -	if (pdata->filter != NULL) {
> -		if (pdata->filter_init != NULL) {
> -			err = pdata->filter_init(pdata, &ts->filter_data);
> -			if (err < 0)
> -				goto err_free_mem;
> -		}
> -		ts->filter = pdata->filter;
> -		ts->filter_cleanup = pdata->filter_cleanup;
> -	} else if (pdata->debounce_max) {
> -		ts->debounce_max = pdata->debounce_max;
> -		if (ts->debounce_max < 2)
> -			ts->debounce_max = 2;
> -		ts->debounce_tol = pdata->debounce_tol;
> -		ts->debounce_rep = pdata->debounce_rep;
> -		ts->filter = ads7846_debounce_filter;
> -		ts->filter_data = ts;
> -	} else {
> -		ts->filter = ads7846_no_filter;
> -	}
> -
>  	err = ads7846_setup_pendown(spi, ts, pdata);
>  	if (err)
>  		goto err_cleanup_filter;
>  
> -	if (pdata->penirq_recheck_delay_usecs)
> -		ts->penirq_recheck_delay_usecs =
> -				pdata->penirq_recheck_delay_usecs;
> -
>  	ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
>  
>  	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
> @@ -1424,7 +1256,7 @@ static int ads7846_probe(struct spi_device *spi)
>  	 * the touchscreen, in case it's not connected.
>  	 */
>  	if (ts->model == 7845)
> -		ads7845_read12_ser(&spi->dev, PWRDOWN);
> +		ads7846_read12_ser(&spi->dev, PWRDOWN);
>  	else
>  		(void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));
>  
> @@ -1465,7 +1297,6 @@ static int ads7846_probe(struct spi_device *spi)
>  		ts->filter_cleanup(ts->filter_data);
>   err_free_mem:
>  	input_free_device(input_dev);
> -	kfree(packet);
>  	kfree(ts);
>  	return err;
>  }
> @@ -1496,7 +1327,6 @@ static int ads7846_remove(struct spi_device *spi)
>  	if (ts->filter_cleanup)
>  		ts->filter_cleanup(ts->filter_data);
>  
> -	kfree(ts->packet);
>  	kfree(ts);
>  
>  	dev_dbg(&spi->dev, "unregistered touchscreen\n");
> diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h
> index 6b8022c625a3..95d616797f52 100644
> --- a/include/linux/spi/ads7846.h
> +++ b/include/linux/spi/ads7846.h
> @@ -23,19 +23,6 @@ struct ads7846_platform_data {
>  	bool	invert_x;		/* Invert x axis */
>  	bool	invert_y;		/* Invert y axis */
>  
> -	/* Settling time of the analog signals; a function of Vcc and the
> -	 * capacitance on the X/Y drivers.  If set to non-zero, two samples
> -	 * are taken with settle_delay us apart, and the second one is used.
> -	 * ~150 uSec with 0.01uF caps.
> -	 */
> -	u16	settle_delay_usecs;
> -
> -	/* If set to non-zero, after samples are taken this delay is applied
> -	 * and penirq is rechecked, to help avoid false events.  This value
> -	 * is affected by the material used to build the touch layer.
> -	 */
> -	u16	penirq_recheck_delay_usecs;
> -
>  	u16	x_plate_ohms;
>  	u16	y_plate_ohms;
>  
> @@ -43,15 +30,19 @@ struct ads7846_platform_data {
>  	u16	y_min, y_max;
>  	u16	pressure_min, pressure_max;
>  
> -	u16	debounce_max;		/* max number of additional readings
> -					 * per sample */
> -	u16	debounce_tol;		/* tolerance used for filtering */
> -	u16	debounce_rep;		/* additional consecutive good readings
> -					 * required after the first two */
>  	int	gpio_pendown;		/* the GPIO used to decide the pendown
>  					 * state if get_pendown_state == NULL */
>  	int	gpio_pendown_debounce;	/* platform specific debounce time for
>  					 * the gpio_pendown */
> +	unsigned int skip_samples;	/* Skip n (<=2) samples after switching
> +					 * plates. */
> +	unsigned int rt_threshold;	/* Rt threshold for valid touch */
> +	unsigned int filter_tolerance;	/* Filter X/Y tolerance (raw) */
> +	unsigned int sample_period;	/* Touchscreen sample period in ms */
> +	unsigned int report_period;	/* Touchscreen reporting period in ms.
> +					 * Must be a multiple of sample_period */
> +	unsigned int pendown_glitch_max; /* Maximum samples of pendown signal
> +					  * glitch */
>  	int	(*get_pendown_state)(void);
>  	int	(*filter_init)	(const struct ads7846_platform_data *pdata,
>  				 void **filter_data);

Best regards,

-- 
David Jander
Protonic Holland.




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux