maXTouch: Fix some issues with interrupt handling

This commit is contained in:
Gregory Nutt 2014-07-07 13:25:20 -06:00
parent eb4dae548c
commit ab8506163a
2 changed files with 60 additions and 28 deletions

View File

@ -269,7 +269,7 @@ int arch_tcinitialize(int minor)
/* Configure maXTouch CHG interrupts */ /* Configure maXTouch CHG interrupts */
sam_pioirq(IRQ_CHG_MXT); sam_pioirq(PIO_CHG_MXT);
(void)irq_attach(IRQ_CHG_MXT, mxt_interrupt); (void)irq_attach(IRQ_CHG_MXT, mxt_interrupt);
/* Initialize and register the I2C touchscreen device */ /* Initialize and register the I2C touchscreen device */

View File

@ -233,7 +233,7 @@ static int mxt_poll(FAR struct file *filep, struct pollfd *fds, bool setup);
static int mxt_getinfo(struct mxt_dev_s *priv); static int mxt_getinfo(struct mxt_dev_s *priv);
static int mxt_getobjtab(FAR struct mxt_dev_s *priv); static int mxt_getobjtab(FAR struct mxt_dev_s *priv);
static int mxt_chghigh(FAR struct mxt_dev_s *priv); static int mxt_clrpending(FAR struct mxt_dev_s *priv);
static int mxt_hwinitialize(FAR struct mxt_dev_s *priv); static int mxt_hwinitialize(FAR struct mxt_dev_s *priv);
/**************************************************************************** /****************************************************************************
@ -269,6 +269,8 @@ static int mxt_getreg(FAR struct mxt_dev_s *priv, uint16_t regaddr,
uint8_t addrbuf[2]; uint8_t addrbuf[2];
int ret; int ret;
ivdbg("regaddr:%04x buflen=%d\n", regaddr, buflen);
/* Set up to write the address */ /* Set up to write the address */
addrbuf[0] = regaddr & 0xff; addrbuf[0] = regaddr & 0xff;
@ -310,6 +312,8 @@ static int mxt_putreg(FAR struct mxt_dev_s *priv, uint16_t regaddr,
uint8_t addrbuf[2]; uint8_t addrbuf[2];
int ret; int ret;
ivdbg("regaddr:%04x buflen=%d\n", regaddr, buflen);
/* Set up to write the address */ /* Set up to write the address */
addrbuf[0] = regaddr & 0xff; addrbuf[0] = regaddr & 0xff;
@ -378,8 +382,9 @@ static int mxt_getmessage(FAR struct mxt_dev_s *priv,
uint16_t regaddr; uint16_t regaddr;
object = mxt_object(priv, MXT_GEN_MESSAGE_T5); object = mxt_object(priv, MXT_GEN_MESSAGE_T5);
if (!object) if (object == NULL)
{ {
idbg("ERROR: mxt_object failed\n");
return -EINVAL; return -EINVAL;
} }
@ -635,15 +640,17 @@ static void mxt_touch_event(FAR struct mxt_dev_s *priv,
sample = &priv->sample[ndx]; sample = &priv->sample[ndx];
if ((status & MXT_DETECT) == 0) if ((status & MXT_DETECT) == 0)
{ {
/* Ignore the event if the if there was no contact: /* Ignore the event if there was no contact to be lost:
* *
* CONTACT_NONE = No touch and already reported * CONTACT_NONE = No touch and loss-of-contact already reported
* CONTACT_LOST = No touch, but not reported) * CONTACT_LOST = No touch and unreported loss-of-contact.
*/ */
if (sample->contact == CONTACT_NONE) if (sample->contact == CONTACT_NONE)
{ {
goto errout; /* Return without posting any event */
return;
} }
sample->contact = CONTACT_LOST; sample->contact = CONTACT_LOST;
@ -726,11 +733,6 @@ static void mxt_touch_event(FAR struct mxt_dev_s *priv,
priv->event = true; priv->event = true;
mxt_notify(priv); mxt_notify(priv);
/* Exit, re-enabling maXTouch interrupts */
errout:
priv->lower->enable(priv->lower, true);
} }
/**************************************************************************** /****************************************************************************
@ -743,6 +745,7 @@ static void mxt_worker(FAR void *arg)
FAR const struct mxt_lower_s *lower; FAR const struct mxt_lower_s *lower;
struct mxt_msg_s msg; struct mxt_msg_s msg;
uint8_t id; uint8_t id;
int ret;
ASSERT(priv != NULL); ASSERT(priv != NULL);
@ -759,9 +762,10 @@ static void mxt_worker(FAR void *arg)
{ {
/* Retrieve the next message from the maXTouch */ /* Retrieve the next message from the maXTouch */
if (mxt_getmessage(priv, &msg)) ret = mxt_getmessage(priv, &msg);
if (ret < 0)
{ {
idbg("ERROR: Failed to read msg\n"); idbg("ERROR: mxt_getmessage failed: %d\n", ret);
return; return;
} }
@ -810,7 +814,12 @@ static void mxt_worker(FAR void *arg)
msg.body[4], msg.body[5], msg.body[6]); msg.body[4], msg.body[5], msg.body[6]);
} }
} }
while (id != 0xff); while (id != 0x00 && id != 0xff);
/* Acknowledge and re-enable maXTouch interrupts */
MXT_CLEAR(lower);
MXT_ENABLE(lower);
} }
/**************************************************************************** /****************************************************************************
@ -830,7 +839,7 @@ static int mxt_interrupt(FAR const struct mxt_lower_s *lower, FAR void *arg)
/* Disable further interrupts */ /* Disable further interrupts */
lower->enable(lower, false); MXT_DISABLE(lower);
/* Transfer processing to the worker thread. Since maXTouch interrupts are /* Transfer processing to the worker thread. Since maXTouch interrupts are
* disabled while the work is pending, no special action should be required * disabled while the work is pending, no special action should be required
@ -1406,7 +1415,7 @@ static int mxt_getobjtab(FAR struct mxt_dev_s *priv)
idmax = 0; idmax = 0;
} }
ivdbg("%2d. Type %d Start %d size: %d instances: %d IDs: %u-%u\n", ivdbg("%2d. type %2d addr %04x size: %d instances: %d IDs: %u-%u\n",
i, object->type, MXT_GETUINT16(object->addr), object->size + 1, i, object->type, MXT_GETUINT16(object->addr), object->size + 1,
object->ninstances + 1, idmin, idmax); object->ninstances + 1, idmin, idmax);
@ -1437,36 +1446,45 @@ static int mxt_getobjtab(FAR struct mxt_dev_s *priv)
} }
/**************************************************************************** /****************************************************************************
* Name: mxt_chghigh * Name: mxt_clrpending
*
* Clear any pending messages be reading messages until there are no
* pending messages. This will force the CHG pin to the high state and
* prevent spurious initial interrupts.
*
****************************************************************************/ ****************************************************************************/
static int mxt_chghigh(FAR struct mxt_dev_s *priv) static int mxt_clrpending(FAR struct mxt_dev_s *priv)
{ {
struct mxt_msg_s msg; struct mxt_msg_s msg;
int retries = 10; int retries = 10;
int ret; int ret;
/* Read dummy message to make high CHG pin */ /* Read dummy message until there are no more to read (or until we have
* tried 10 times). NOTE: The MXT748E seems to return msg.id == 0x00
* when there are no pending messages.
*/
do do
{ {
ret = mxt_getmessage(priv, &msg); ret = mxt_getmessage(priv, &msg);
if (ret < 0) if (ret < 0)
{ {
idbg("ERROR: mxt_getmessage failed: %d\n", ret);
return ret; return ret;
} }
} }
while (msg.id != 0xff && --retries > 0); while (msg.id != 0x00 && msg.id != 0xff && --retries > 0);
/* Check for a timeout */ /* Complain if we exceed the retry limit */
if (retries <= 0) if (retries <= 0)
{ {
idbg("ERROR: CHG pin did not clear\n"); idbg("ERROR: CHG pin did not clear: ID=%02x\n", msg.id);
return -EBUSY; return -EBUSY;
} }
return 0; return OK;
} }
/**************************************************************************** /****************************************************************************
@ -1574,22 +1592,29 @@ static int mxt_hwinitialize(FAR struct mxt_dev_s *priv)
goto errout_with_objtab; goto errout_with_objtab;
} }
/* Force the CHG pin to the high state */ /* Clear any pending messages. This will force the CHG pin to the high
* state and prevent spurious interrupts.
*/
ret = mxt_chghigh(priv); ret = mxt_clrpending(priv);
if (ret < 0) if (ret < 0)
{ {
idbg("ERROR: mxt_clrpending failed: %d\n", ret);
goto errout_with_sample; goto errout_with_sample;
} }
return OK; return OK;
/* Error exits */
errout_with_sample: errout_with_sample:
kfree(priv->sample); kfree(priv->sample);
priv->sample = NULL; priv->sample = NULL;
errout_with_objtab: errout_with_objtab:
kfree(priv->objtab); kfree(priv->objtab);
priv->objtab = NULL; priv->objtab = NULL;
return ret; return ret;
} }
@ -1650,7 +1675,7 @@ int mxt_register(FAR struct i2c_dev_s *i2c,
/* Make sure that interrupts are disabled */ /* Make sure that interrupts are disabled */
MXT_CLEAR(lower); MXT_CLEAR(lower);
MXT_ENABLE(lower); MXT_DISABLE(lower);
/* Attach the interrupt handler */ /* Attach the interrupt handler */
@ -1683,7 +1708,14 @@ int mxt_register(FAR struct i2c_dev_s *i2c,
} }
/* Schedule work to perform the initial sampling and to set the data /* Schedule work to perform the initial sampling and to set the data
* availability conditions. */ * availability conditions. The worker will enable MXT interrupts
* when it completes its initialization.
*
* NOTE: At present, this really does nothing for the case of the MXT
* driver. This could be replaced with MXT_ENABLE(lower). Or,
* alternatively, eliminate mxt_clrpending() which does basically the
* same thing.
*/
ret = work_queue(HPWORK, &priv->work, mxt_worker, priv, 0); ret = work_queue(HPWORK, &priv->work, mxt_worker, priv, 0);
if (ret != 0) if (ret != 0)