SAMA5 TSD: Fix to prohibit reading samples when not valid

This commit is contained in:
Gregory Nutt 2013-10-17 17:26:06 -06:00
parent 8924101566
commit 2d831bc717

View File

@ -99,14 +99,10 @@
/* Data read bit definitions */
#define TSD_XREADY (1 << 0) /* X value is ready */
#define TSD_YREADY (1 << 1) /* Y value is ready */
#ifdef CONFIG_SAMA5_TSD_4WIRE
# define TSD_PREADY (1 << 2) /* Pressure value is ready */
# define TSD_ALLREADY (TSD_XREADY | TSD_YREADY | TSD_PREADY)
# define TSD_ALLREADY (ADC_INT_XRDY | ADC_INT_YRDY | ADC_INT_PRDY)
#else
# define TSD_ALLREADY (TSD_XREADY | TSD_YREADY)
# define TSD_ALLREADY (ADC_INT_XRDY | ADC_INT_YRDY)
#endif
/* Pen sample state bit sets */
@ -175,7 +171,6 @@ struct sam_tsd_s
volatile bool penchange; /* An unreported event is buffered */
uint32_t threshx; /* Thresholding X value */
uint32_t threshy; /* Thresholding Y value */
volatile uint32_t pending; /* Pending interrupt set set */
sem_t waitsem; /* Used to wait for the availability of data */
struct sam_adc_s *adc; /* ADC device handle */
@ -204,7 +199,7 @@ static int sam_tsd_sample(struct sam_tsd_s *priv, struct sam_sample_s *sample);
static int sam_tsd_waitsample(struct sam_tsd_s *priv,
struct sam_sample_s *sample);
static void sam_tsd_bottomhalf(void *arg);
static int sam_tsd_schedule(struct sam_tsd_s *priv, uint32_t pending);
static int sam_tsd_schedule(struct sam_tsd_s *priv);
static void sam_tsd_expiry(int argc, uint32_t arg1, ...);
/* Character driver methods */
@ -528,9 +523,9 @@ static void sam_tsd_bottomhalf(void *arg)
ASSERT(priv != NULL);
/* Get the set of unmasked, pending ADC interrupts */
/* Get the set of pending ADC interrupts and pen status */
pending = priv->pending;
pending = sam_adc_getreg(priv->adc, SAM_ADC_ISR);
/* Get exclusive access to the driver data structure */
@ -552,10 +547,6 @@ static void sam_tsd_bottomhalf(void *arg)
priv->threshx = INVALID_THRESHOLD;
priv->threshy = INVALID_THRESHOLD;
/* Clear data validity bits: There is no valid data to be sampled */
priv->valid = 0;
/* We will enable only the ADC_INT_PEN interrupt on exit. We don't
* want to hear anything from the touchscreen until the next touch.
*/
@ -611,54 +602,26 @@ static void sam_tsd_bottomhalf(void *arg)
}
else
{
/* The pen is down and the driver has accepted the last sample values.
* check if we have accumulated all of the samples that we need.
*/
/* The pen is down and the driver has accepted the last sample values. */
/* Check X data availability */
if ((pending & ADC_INT_XRDY) != 0)
{
priv->valid |= TSD_XREADY;
}
/* Check Y data availability */
if ((pending & ADC_INT_YRDY) != 0)
{
priv->valid |= TSD_YREADY;
}
#ifdef CONFIG_SAMA5_TSD_4WIRE
/* Check pressure data availability: (X/1024)*[(Z2/Z1)-1] */
if ((pending & ADC_INT_PRDY) != 0)
{
priv->valid |= TSD_PREADY;
}
#endif
ivdbg("valid: %02x\n", priv->valid);
/* While the pen is down we want interrupts on all day ready an pen
/* While the pen is down we want interrupts on all data ready and pen
* release events.
*/
ier = ADC_TSD_RELEASEINTS;
/* Check if all data is ready. If not, just re-enable interrupts and
* wait until it is.
/* Check if all of the date that we need is available. If not, just
* re-enable interrupts and wait until it is.
*/
if ((priv->valid & TSD_ALLREADY) != TSD_ALLREADY)
if ((pending & TSD_ALLREADY) != TSD_ALLREADY)
{
/* But don't enable interrupts for the data that we already have */
ier &= ~(pending & TSD_ALLREADY);
goto ignored;
}
/* Clear data ready bits in the data validity bitset */
priv->valid = 0;
/* Sample positional values. Get raw X and Y position data */
regval = sam_adc_getreg(priv->adc, SAM_ADC_XPOSR);
@ -676,6 +639,14 @@ static void sam_tsd_bottomhalf(void *arg)
pressr = sam_adc_getreg(priv->adc, SAM_ADC_PRESSR);
#endif
/* Discard any bad readings. This check may not be necessary. */
if (xraw == 0 || xraw >= xscale || yraw == 0 || yraw > yscale)
{
idbg("Discarding: x %d:%d y %d:%d\n", xraw, xscale);
goto ignored;
}
/* Scale the X/Y measurements. The scale value is the maximum
* value that the sample can attain. It should be close to 4095.
* Scaling:
@ -691,6 +662,7 @@ static void sam_tsd_bottomhalf(void *arg)
x = ((xraw << 12) - xraw) / xscale;
y = ((yraw << 12) - yraw) / yscale;
#endif
/* Perform a thresholding operation so that the results will be
* more stable. If the difference from the last sample is small,
* then ignore the event. REVISIT: Should a large change in
@ -722,13 +694,13 @@ static void sam_tsd_bottomhalf(void *arg)
/* When we see a big difference, snap to the new x/y thresholds */
priv->threshx = x;
priv->threshy = y;
priv->threshx = x;
priv->threshy = y;
/* Update the x/y position in the sample data */
priv->sample.x = MIN(x, UINT16_MAX);
priv->sample.y = MIN(y, UINT16_MAX);
priv->sample.x = MIN(x, UINT16_MAX);
priv->sample.y = MIN(y, UINT16_MAX);
#ifdef CONFIG_SAMA5_TSD_4WIRE
/* Scale the pressure and update the pressure in the sample data.
@ -741,9 +713,9 @@ static void sam_tsd_bottomhalf(void *arg)
* Rp = Rxp * (Xraw / 1024) * [(Z2 / Z1) - 1]
*/
z2 = (pressr & ADC_PRESSR_Z2_MASK) >> ADC_PRESSR_Z2_SHIFT;
z1 = (pressr & ADC_PRESSR_Z1_MASK) >> ADC_PRESSR_Z1_SHIFT;
p = CONFIG_SAMA_TSD_RXP * xraw * (z2 - z1) / z1;
z2 = (pressr & ADC_PRESSR_Z2_MASK) >> ADC_PRESSR_Z2_SHIFT;
z1 = (pressr & ADC_PRESSR_Z1_MASK) >> ADC_PRESSR_Z1_SHIFT;
p = CONFIG_SAMA_TSD_RXP * xraw * (z2 - z1) / z1;
priv->sample.p = MIN(p, UINT16_MAX);
#endif
@ -801,7 +773,7 @@ ignored:
* Name: sam_tsd_schedule
****************************************************************************/
static int sam_tsd_schedule(struct sam_tsd_s *priv, uint32_t pending)
static int sam_tsd_schedule(struct sam_tsd_s *priv)
{
int ret;
@ -817,12 +789,6 @@ static int sam_tsd_schedule(struct sam_tsd_s *priv, uint32_t pending)
sam_adc_putreg(priv->adc, SAM_ADC_IDR, ADC_TSD_ALLINTS);
/* Save the set of pending interrupts for the bottom half (in case any
* were cleared by reading the ISR.
*/
priv->pending = pending;
/* Transfer processing to the worker thread. Since touchscreen ADC interrupts are
* disabled while the work is pending, no special action should be required
* to protected the work queue.
@ -850,24 +816,10 @@ static int sam_tsd_schedule(struct sam_tsd_s *priv, uint32_t pending)
static void sam_tsd_expiry(int argc, uint32_t arg1, ...)
{
struct sam_tsd_s *priv = (struct sam_tsd_s *)((uintptr_t)arg1);
uint32_t isr;
uint32_t imr;
uint32_t pending;
/* Get the set of unmasked, pending ADC interrupts. There should be no
* pending TSD interrupts, but we need to get the PENS status bit as a
* minimum.
*/
/* Schedule touchscreen work */
isr = sam_adc_getreg(priv->adc, SAM_ADC_ISR);
imr = sam_adc_getreg(priv->adc, SAM_ADC_IMR);
pending = isr & (imr | ADC_SR_PENS);
/* There should be no pending TSD interrupts, but we need to get the PENS
* status bit as a minimum.
*/
(void)sam_tsd_schedule(priv, pending);
(void)sam_tsd_schedule(priv);
}
/****************************************************************************
@ -1673,7 +1625,6 @@ static void sam_tsd_uninitialize(struct sam_tsd_s *priv)
priv->sample.contact = CONTACT_NONE;
priv->sample.valid = false;
priv->valid = 0;
}
/****************************************************************************
@ -1769,7 +1720,7 @@ void sam_tsd_interrupt(uint32_t pending)
* worker thread.
*/
ret = sam_tsd_schedule(priv, pending);
ret = sam_tsd_schedule(priv);
if (ret < 0)
{
idbg("ERROR: sam_tsd_schedule failed: %d\n", ret);