From 8501188ee242079af26540687830573ab4546591 Mon Sep 17 00:00:00 2001
From: patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>
Date: Sat, 30 Jul 2011 15:31:23 +0000
Subject: [PATCH] More TSC2007 driver updates

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3830 42af7a65-404d-4744-a932-0658087f49c3
---
 arch/arm/src/stm32/stm32_i2c.c   |  37 +--
 configs/vsn/src/sif.c            |   2 +-
 drivers/input/tsc2007.c          | 546 ++++++++++++++++++++++++++-----
 drivers/input/tsc2007.h          |  15 +-
 drivers/wireless/cc1101/cc1101.c |   3 +-
 include/nuttx/i2c.h              |  29 +-
 include/nuttx/input/tsc2007.h    |  35 +-
 include/nuttx/wqueue.h           |   2 +-
 8 files changed, 520 insertions(+), 149 deletions(-)

diff --git a/arch/arm/src/stm32/stm32_i2c.c b/arch/arm/src/stm32/stm32_i2c.c
index 84f099ba1f..91a0aca34d 100644
--- a/arch/arm/src/stm32/stm32_i2c.c
+++ b/arch/arm/src/stm32/stm32_i2c.c
@@ -62,6 +62,10 @@
  *  - Be ready for IPMI
  **/
 
+/************************************************************************************
+ * Included Files
+ ************************************************************************************/
+
 #include <nuttx/config.h>
 #include <nuttx/arch.h>
 #include <nuttx/irq.h>
@@ -84,7 +88,6 @@
 #include "stm32_i2c.h"
 #include "stm32_waste.h"
 
-
 #if defined(CONFIG_STM32_I2C1) || defined(CONFIG_STM32_I2C2)
 
 /************************************************************************************
@@ -108,7 +111,6 @@ struct stm32_i2c_priv_s {
     uint32_t    status;
 };
 
-
 /** I2C Device, Instance
  */
 struct stm32_i2c_inst_s {
@@ -120,7 +122,6 @@ struct stm32_i2c_inst_s {
     uint16_t    flags;
 };
 
-
 /************************************************************************************
  * Private Data
  ************************************************************************************/
@@ -139,7 +140,6 @@ struct stm32_i2c_priv_s stm32_i2c2_priv = {
 };
 #endif
 
-
 /************************************************************************************
  * Private Functions
  ************************************************************************************/
@@ -150,21 +150,18 @@ static inline uint16_t stm32_i2c_getreg(FAR struct stm32_i2c_priv_s *priv, uint8
     return getreg16(priv->base + offset);
 }
 
-
 /** Put register value by offset */
 static inline void stm32_i2c_putreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint16_t value)
 {
     putreg16(value, priv->base + offset);
 }
 
-
 /** Modify register value by offset */
 static inline void stm32_i2c_modifyreg(FAR struct stm32_i2c_priv_s *priv, uint8_t offset, uint16_t clearbits, uint16_t setbits)
 {
     modifyreg16(priv->base + offset, clearbits, setbits);
 }
 
-
 void inline stm32_i2c_sem_wait(FAR struct i2c_dev_s *dev)
 {
     while( sem_wait( &((struct stm32_i2c_inst_s *)dev)->priv->sem_excl ) != 0 ) {
@@ -172,7 +169,6 @@ void inline stm32_i2c_sem_wait(FAR struct i2c_dev_s *dev)
     }
 }
 
-
 int inline stm32_i2c_sem_waitisr(FAR struct i2c_dev_s *dev)
 {
     while( sem_wait( &((struct stm32_i2c_inst_s *)dev)->priv->sem_isr ) != 0 ) {
@@ -181,27 +177,23 @@ int inline stm32_i2c_sem_waitisr(FAR struct i2c_dev_s *dev)
     return OK;
 }
 
-
 void inline stm32_i2c_sem_post(FAR struct i2c_dev_s *dev)
 {
     sem_post( &((struct stm32_i2c_inst_s *)dev)->priv->sem_excl );
 }
 
-
 void inline stm32_i2c_sem_init(FAR struct i2c_dev_s *dev)
 {
     sem_init( &((struct stm32_i2c_inst_s *)dev)->priv->sem_excl, 0, 1);
     sem_init( &((struct stm32_i2c_inst_s *)dev)->priv->sem_isr, 0, 0);
 }
 
-
 void inline stm32_i2c_sem_destroy(FAR struct i2c_dev_s *dev)
 {
     sem_destroy( &((struct stm32_i2c_inst_s *)dev)->priv->sem_excl );
     sem_destroy( &((struct stm32_i2c_inst_s *)dev)->priv->sem_isr );
 }
 
-
 static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequency)
 {
     /* Disable Peripheral if rising time is to be changed, 
@@ -238,20 +230,17 @@ static void stm32_i2c_setclock(FAR struct stm32_i2c_priv_s *priv, uint32_t frequ
         stm32_i2c_putreg(priv, STM32_I2C_CR1_OFFSET, cr1);
 }
 
-
 static inline void stm32_i2c_sendstart(FAR struct stm32_i2c_priv_s *priv)
 {
     /* Disable ACK on receive by default and generate START */
     stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, I2C_CR1_START);
 }
 
-
 static inline void stm32_i2c_sendstop(FAR struct stm32_i2c_priv_s *priv)
 {
     stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, I2C_CR1_STOP);
 }
 
-
 static inline uint32_t stm32_i2c_getstatus(FAR struct stm32_i2c_priv_s *priv)
 {
    uint32_t status = stm32_i2c_getreg(priv, STM32_I2C_SR1_OFFSET);
@@ -259,7 +248,6 @@ static inline uint32_t stm32_i2c_getstatus(FAR struct stm32_i2c_priv_s *priv)
    return status;
 }
 
-
 /************************************************************************************
  * Interrupt Service Routines
  ************************************************************************************/
@@ -425,8 +413,6 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s * priv)
     priv->status = status;
     return OK;
 }
- 
-
 
 /* Decode ***************************************************************************/
 
@@ -444,7 +430,6 @@ static int stm32_i2c2_isr(int irq, void *context)
 }
 #endif
 
-
 /************************************************************************************
  * Private Initialization and Deinitialization
  ************************************************************************************/
@@ -511,7 +496,6 @@ static int stm32_i2c_init(FAR struct stm32_i2c_priv_s *priv)
     return OK;
 }
 
-
 /** Shutdown the I2C hardware  */
 static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv)
 {
@@ -555,7 +539,6 @@ static int stm32_i2c_deinit(FAR struct stm32_i2c_priv_s *priv)
     return OK;
 }
 
-
 /************************************************************************************
  * Device Driver OPS - Blocking Type
  ************************************************************************************/
@@ -574,7 +557,6 @@ uint32_t stm32_i2c_setfrequency(FAR struct i2c_dev_s *dev, uint32_t frequency)
     return ((struct stm32_i2c_inst_s *)dev)->frequency;
 }
 
-
 int stm32_i2c_setaddress(FAR struct i2c_dev_s *dev, int addr, int nbits)
 {
     stm32_i2c_sem_wait(dev);
@@ -586,7 +568,6 @@ int stm32_i2c_setaddress(FAR struct i2c_dev_s *dev, int addr, int nbits)
     return OK;
 }
 
-
 int stm32_i2c_process(FAR struct i2c_dev_s *dev, FAR struct i2c_msg_s *msgs, int count)
 {
     struct stm32_i2c_inst_s *inst = (struct stm32_i2c_inst_s *)dev;
@@ -666,7 +647,6 @@ int stm32_i2c_process(FAR struct i2c_dev_s *dev, FAR struct i2c_msg_s *msgs, int
     return -status_errno;
 }
 
-  
 int stm32_i2c_write(FAR struct i2c_dev_s *dev, const uint8_t *buffer, int buflen)
 {
     stm32_i2c_sem_wait(dev);   /* ensure that address or flags don't change meanwhile */
@@ -681,7 +661,6 @@ int stm32_i2c_write(FAR struct i2c_dev_s *dev, const uint8_t *buffer, int buflen
     return stm32_i2c_process(dev, &msgv, 1);
 }
 
-
 int stm32_i2c_read(FAR struct i2c_dev_s *dev, uint8_t *buffer, int buflen)
 {
     stm32_i2c_sem_wait(dev);   /* ensure that address or flags don't change meanwhile */
@@ -696,7 +675,6 @@ int stm32_i2c_read(FAR struct i2c_dev_s *dev, uint8_t *buffer, int buflen)
     return stm32_i2c_process(dev, &msgv, 1);
 }
 
-
 #ifdef CONFIG_I2C_WRITEREAD
 int stm32_i2c_writeread(FAR struct i2c_dev_s *dev, const uint8_t *wbuffer, int wbuflen,
                         uint8_t *buffer, int buflen)
@@ -722,7 +700,6 @@ int stm32_i2c_writeread(FAR struct i2c_dev_s *dev, const uint8_t *wbuffer, int w
 }
 #endif
 
-
 #ifdef CONFIG_I2C_TRANSFER
 int stm32_i2c_transfer(FAR struct i2c_dev_s *dev, FAR struct i2c_msg_s *msgs, int count)
 {
@@ -731,7 +708,6 @@ int stm32_i2c_transfer(FAR struct i2c_dev_s *dev, FAR struct i2c_msg_s *msgs, in
 }
 #endif
 
-
 /************************************************************************************
  * Device Structures, Instantiation
  ************************************************************************************/
@@ -740,9 +716,9 @@ struct i2c_ops_s stm32_i2c_ops = {
     .setfrequency       = stm32_i2c_setfrequency,
     .setaddress         = stm32_i2c_setaddress,
     .write              = stm32_i2c_write,
-    .read               = stm32_i2c_read,
+    .read               = stm32_i2c_read
 #ifdef CONFIG_I2C_WRITEREAD
-    .writeread          = stm32_i2c_writeread
+  , .writeread          = stm32_i2c_writeread
 #endif
 #ifdef CONFIG_I2C_TRANSFER
   , .transfer           = stm32_i2c_transfer
@@ -753,7 +729,6 @@ struct i2c_ops_s stm32_i2c_ops = {
 #endif
 };
 
-
 /************************************************************************************
  * Public Function - Initialization
  ************************************************************************************/
diff --git a/configs/vsn/src/sif.c b/configs/vsn/src/sif.c
index 456f38a30f..0e08280dec 100644
--- a/configs/vsn/src/sif.c
+++ b/configs/vsn/src/sif.c
@@ -496,7 +496,7 @@ int sif_init(void)
  * Provides direct access to the sensor connector, readings, and diagnostic.
  **/
  
-extern int cc1101_eventcb(int irq, FAR void *context)
+extern int cc1101_eventcb(int irq, FAR void *context);
  
 int sif_main(int argc, char *argv[])
 {
diff --git a/drivers/input/tsc2007.c b/drivers/input/tsc2007.c
index 919952285f..7af6711bc2 100644
--- a/drivers/input/tsc2007.c
+++ b/drivers/input/tsc2007.c
@@ -38,6 +38,11 @@
  *
  ****************************************************************************/
 
+/* The TSC2007 is an analog interface circuit for a human interface touch
+ * screen device. All peripheral functions are controlled through the command
+ * byte and onboard state machines.
+ */
+
 /****************************************************************************
  * Included Files
  ****************************************************************************/
@@ -50,6 +55,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <string.h>
+#include <fcntl.h>
 #include <semaphore.h>
 #include <poll.h>
 #include <errno.h>
@@ -60,6 +66,7 @@
 #include <nuttx/arch.h>
 #include <nuttx/fs.h>
 #include <nuttx/i2c.h>
+#include <nuttx/wqueue.h>
 #include <nuttx/input/tsc2007.h>
 
 #include "tsc2007.h"
@@ -78,14 +85,33 @@
 /****************************************************************************
  * Private Types
  ****************************************************************************/
+/* This structure describes the results of one TSC2007 sample */
+
+struct tsc2007_sample_s
+{
+  bool     pendown;                    /* Pen down state */
+  uint16_t x;                          /* Measured X position */
+  uint16_t y;                          /* Measured Y position */
+  uint16_t pressure;                   /* Calculated pressure */
+};
+
+/* This structure describes the state of one TSC2007 driver instance */
 
 struct tsc2007_dev_s
 {
-  uint8_t               crefs;    /* Number of times the device has been opened */
-  sem_t                 devsem;   /* Manages exclusive access to this structure */
+#ifdef CONFIG_TSC2007_MULTIPLE
+  FAR struct tsc2007_dev_s *flink;     /* Supports a singly linked list of drivers */
+#endif
+  uint8_t crefs;                       /* Number of times the device has been opened */
+  uint8_t nwaiters;                    /* Number of threads waiting for TSC2007 data */
+  volatile bool penchange;             /* An unreported event is buffered */
+  sem_t devsem;                        /* Manages exclusive access to this structure */
+  sem_t waitsem;                       /* Used to wait for the availability of data */
 
   FAR struct tsc2007_config_s *config; /* Board configuration data */
-  FAR struct i2c_dev_s *i2c;      /* Saved I2C driver instance */
+  FAR struct i2c_dev_s *i2c;           /* Saved I2C driver instance */
+  struct work_s work;                  /* Supports the interrupt handling "bottom half" */
+  struct tsc2007_sample_s sample;      /* Last sampled data */
 
   /* The following is a list if poll structures of threads waiting for
    * driver events. The 'struct pollfd' reference for each open is also
@@ -93,20 +119,21 @@ struct tsc2007_dev_s
    */
 
 #ifndef CONFIG_DISABLE_POLL
-  struct pollfd        *fds[CONFIG_TSC2007_NPOLLWAITERS];
+  struct pollfd *fds[CONFIG_TSC2007_NPOLLWAITERS];
 #endif
 };
 
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
-#ifndef CONFIG_DISABLE_POLL
-static void tsc2007_pollnotify(FAR struct tsc2007_dev_s *priv,
-                               pollevent_t eventset);
-#endif
+
+static void tsc2007_notify(FAR struct tsc2007_dev_s *priv);
+static int tsc2007_sample(FAR struct tsc2007_dev_s *priv,
+                          FAR struct tsc2007_sample_s *sample);
+static int tsc2007_waitsample(FAR struct tsc2007_dev_s *priv,
+                              FAR struct tsc2007_sample_s *sample);
 static int tsc2007_transfer(FAR struct tsc2007_dev_s *priv, uint8_t cmd);
-static void tsc2007_sample(FAR struct tsc2007_dev_s *tsc,
-                           FAR struct tsc2007_sample_s *sample);
+static void tsc2007_worker(FAR void *arg);
 static int tsc2007_interrupt(int irq, FAR void *context);
 
 /* Character driver methods */
@@ -114,7 +141,6 @@ static int tsc2007_interrupt(int irq, FAR void *context);
 static int tsc2007_open(FAR struct file *filep);
 static int tsc2007_close(FAR struct file *filep);
 static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len);
-static ssize_t tsc2007_write(FAR struct file *filep, FAR const char *buffer, size_t len);
 static int tsc2007_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
 #ifndef CONFIG_DISABLE_POLL
 static int tsc2007_poll(FAR struct file *filep, struct pollfd *fds, bool setup);
@@ -124,12 +150,14 @@ static int tsc2007_poll(FAR struct file *filep, struct pollfd *fds, bool setup);
  * Private Data
  ****************************************************************************/
 
+/* This the the vtable that supports the character driver interface */
+
 static const struct file_operations tsc2007_fops =
 {
   tsc2007_open,    /* open */
   tsc2007_close,   /* close */
   tsc2007_read,    /* read */
-  tsc2007_write,   /* write */
+  0,               /* write */
   0,               /* seek */
   tsc2007_ioctl    /* ioctl */
 #ifndef CONFIG_DISABLE_POLL
@@ -137,37 +165,176 @@ static const struct file_operations tsc2007_fops =
 #endif
 };
 
+/* If only a single TSC2007 device is supported, then the driver state
+ * structure may as well be pre-allocated.
+ */
+
+#ifndef CONFIG_TSC2007_MULTIPLE
+static struct tsc2007_dev_s g_tsc2007;
+
+/* Otherwise, we will need to maintain allocated driver instances in a list */
+
+#else
+static struct tsc2007_dev_s *g_tsc2007list;
+#endif
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
 
 /****************************************************************************
- * Name: tsc2007_pollnotify
+ * Name: tsc2007_notify
  ****************************************************************************/
 
-#ifndef CONFIG_DISABLE_POLL
-static void tsc2007_pollnotify(FAR struct tsc2007_dev_s *priv,
-                               pollevent_t eventset)
+static void tsc2007_notify(FAR struct tsc2007_dev_s *priv)
 {
+#ifndef CONFIG_DISABLE_POLL
   int i;
+#endif
+
+  /* If there are threads waiting for read data, then signal one of them
+   * that the read data is available.
+   */
+
+  if (priv->nwaiters > 0)
+    {
+      /* After posting this semaphore, we need to exit because the TSC2007
+       * is no longer avaialable.
+       */
+
+      sem_post(&priv->waitsem); 
+    }
 
+  /* If there are threads waiting on poll() for TSC2007 data to become availabe,
+   * then wake them up now.  NOTE: we wake up all waiting threads because we
+   * do not know that they are going to do.  If they all try to read the data,
+   * then some make end up blocking after all.
+   */
+
+#ifndef CONFIG_DISABLE_POLL
   for (i = 0; i < CONFIG_TSC2007_NPOLLWAITERS; i++)
     {
       struct pollfd *fds = priv->fds[i];
       if (fds)
         {
-          fds->revents |= (fds->events & eventset);
-          if (fds->revents != 0)
-            {
-              ivdbg("Report events: %02x\n", fds->revents);
-              sem_post(fds->sem);
-            }
+          fds->revents |= POLLIN;
+          ivdbg("Report events: %02x\n", fds->revents);
+          sem_post(fds->sem);
         }
     }
-}
-#else
-#  define tsc2007_pollnotify(priv,event)
 #endif
+}
+
+/****************************************************************************
+ * Name: tsc2007_sample
+ ****************************************************************************/
+
+static int tsc2007_sample(FAR struct tsc2007_dev_s *priv,
+                          FAR struct tsc2007_sample_s *sample)
+{
+  irqstate_t flags;
+  int ret = -EAGAIN;
+
+  /* Interrupts me be disabled when this is called to (1) prevent posting
+   * of semphores from interrupt handlers, and (2) to prevent sampled data
+   * from changing until it has been reported.
+   */
+
+  flags = irqsave();
+
+  /* Is there new TSC2007 sample data available? */
+
+  if (priv->penchange)
+    {
+      /* Yes.. the state has changed in some way.  Return a copy of the
+       * sampled data.
+       */
+
+      memcpy(sample, &priv->sample, sizeof(struct tsc2007_sample_s ));
+      priv->penchange = false;
+      ret = OK;
+    }
+
+  irqrestore(flags);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: tsc2007_waitsample
+ ****************************************************************************/
+
+static int tsc2007_waitsample(FAR struct tsc2007_dev_s *priv,
+                              FAR struct tsc2007_sample_s *sample)
+{
+  irqstate_t flags;
+  int ret;
+
+  /* Interrupts me be disabled when this is called to (1) prevent posting
+   * of semphores from interrupt handlers, and (2) to prevent sampled data
+   * from changing until it has been reported.
+   *
+   * In addition, we will also disable pre-emption to prevent other threads
+   * from getting control while we muck with the semaphores.
+   */
+
+  sched_lock();
+  flags = irqsave();
+
+  /* Now release the semaphore that manages mutually exclusive access to
+   * the device structure.  This may cause other tasks to become ready to
+   * run, but they cannot run yet because pre-emption is disabled.
+   */
+
+  sem_post(&priv->devsem);
+
+  /* Try to get the a sample... if we cannot, then wait on the semaphore
+   * that is posted when new sample data is availble.
+   */
+
+  while (tsc2007_sample(priv, sample) < 0)
+    {
+      /* Wait for a change in the TSC2007 state */
+ 
+      priv->nwaiters++;
+      ret = sem_wait(&priv->waitsem);
+      priv->nwaiters--;
+
+      if (ret < 0)
+        {
+          /* If we are awakened by a signal, then we need to return
+           * the failure now.
+           */
+
+          DEBUGASSERT(errno == EINTR);
+          ret = -EINTR;
+          goto errout;
+        }
+    }
+
+  /* Re-acquire the the semaphore that manages mutually exclusive access to
+   * the device structure.  We may have to wait here.  But we have our sample.
+   * Interrupts and pre-emption will be re-enabled while we wait.
+   */
+
+  ret = sem_wait(&priv->devsem);
+
+errout:
+  /* Then re-enable interrupts.  We might get interrupt here and there
+   * could be a new sample.  But no new threads will run because we still
+   * have pre-emption disabled.
+   */
+
+  irqrestore(flags);
+
+  /* Restore pre-emption.  We might get suspended here but that is okay
+   * because we already have our sample.  Note:  this means that if there
+   * were two threads reading from the TSC2007 for some reason, the data
+   * might be read out of order.
+   */
+
+  sched_unlock();
+  return ret;
+}
 
 /****************************************************************************
  * Name: tsc2007_transfer
@@ -247,31 +414,159 @@ static int tsc2007_transfer(FAR struct tsc2007_dev_s *priv, uint8_t cmd)
        return ret;
      }
 
-   ret = (unsigned int)data12[0] << 4 | (unsigned int)data12[1];
-   ivdbg(&tsc->client->dev, "data: 0x%03x\n", ret);
+   /* Get the MS 12 bits from the first byte and the remaining LS 4 bits from
+    * the second byte.
+    */
+
+   ret = (unsigned int)data12[0] << 4 | (unsigned int)data12[1] >> 4;
+   ivdbg(&tsc->client->dev, "data: 0x%04x\n", ret);
    return ret;
 }
 
 /****************************************************************************
- * Name: tsc2007_sample
+ * Name: tsc2007_worker
  ****************************************************************************/
 
-static void tsc2007_sample(FAR struct tsc2007_dev_s *tsc,
-                           FAR struct tsc2007_sample_s *sample)
+static void tsc2007_worker(FAR void *arg)
 {
-  /* ADC is on... Disable interrupts and read Y and X positions */
+  FAR struct tsc2007_dev_s    *priv = (FAR struct tsc2007_dev_s *)arg;
+  FAR struct tsc2007_config_s *config;   /* Convenience pointer */
+  bool                         pendown;  /* true: pend is down */
+  uint16_t                     x;        /* X position */
+  uint16_t                     y;        /* Y position */
+  uint16_t                     z1;       /* Z1 position */
+  uint16_t                     z2;       /* Z2 position */
+  uint32_t                     pressure; /* Measured pressure */
+
+  ASSERT(priv != NULL);
+
+  /* Get a pointer the callbacks for convenience (and so the code is not so
+   * ugly).
+   */
+
+  config = priv->config;
+  DEBUGASSERT(config != NULL);
+
+  /* Check for pen up or down by reading the PENIRQ GPIO. */
 
-  sample->y = tsc2007_transfer(tsc, (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YPOS));
-  sample->x = tsc2007_transfer(tsc, (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XPOS));
+  pendown = config->pendown(config);
 
-  /* Read Z1 and Z2 positions */
+  /* Handle the change from pen down to pen up */
 
-  sample->z1 = tsc2007_transfer(tsc, (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z1POS));
-  sample->z2 = tsc2007_transfer(tsc, (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z2POS));
+  if (!pendown)
+    {
+      /* Ignore the interrupt if the pen was already down */
+
+      if (!priv->sample.pendown)
+        {
+          goto errout;
+        }
+    }
+  else
+    {
+      /* Handle all pen down events.  First, sample X, Y, Z1, and Z2 values.
+       *
+       * "A resistive touch screen operates by applying a voltage across a
+       *  resistor network and measuring the change in resistance at a given
+       *  point on the matrix where the screen is touched by an input (stylus,
+       *  pen, or finger). The change in the resistance ratio marks the location
+       *  on the touch screen.
+       *
+       * "The 4-wire touch screen panel works by applying a voltage across the
+       *  vertical or horizontal resistive network.  The A/D converter converts
+       *  the voltage measured at the point where the panel is touched. A measurement
+       *  of the Y position of the pointing device is made by connecting the X+
+       *  input to a data converter chip, turning on the Y+ and Y� drivers, and
+       *  digitizing the voltage seen at the X+ input ..."
+       *
+       * "... it is recommended that whenever the host writes to the TSC2007, the
+       *  master processor masks the interrupt associated to PENIRQ. This masking
+       *  prevents false triggering of interrupts when the PENIRQ line is disabled
+       *  in the cases previously listed."
+       */
+
+      y = tsc2007_transfer(priv,
+                          (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YPOS));
+
+      /* "Voltage is then applied to the other axis, and the A/D converter
+       *  converts the voltage representing the X position on the screen. This
+       *  process provides the X and Y coordinates to the associated processor."
+       */
+
+      x = tsc2007_transfer(priv,
+                          (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XPOS));
+
+      /* "... To determine pen or finger touch, the pressure of the touch must be
+       *  determined. ... There are several different ways of performing this
+       *  measurement. The TSC2007 supports two methods. The first method requires
+       *  knowing the X-plate resistance, the measurement of the X-position, and two
+       *  additional cross panel measurements (Z2 and Z1) of the touch screen."
+       *
+       *  Rtouch = Rxplate * (X / 4096)* (Z2/Z1 - 1)
+       *
+       * "The second method requires knowing both the X-plate and Y-plate
+       *  resistance, measurement of X-position and Y-position, and Z1 ..."
+       *
+       *  Rtouch = Rxplate * (X / 4096) * (4096/Z1 - 1) - Ryplate * (1 - Y/4096)
+       *
+       * Read Z1 and Z2 values.
+       */
 
-  /* Power down ADC and enable PENIRQ */
+      z1 = tsc2007_transfer(priv,
+                           (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z1POS));
+      z2 = tsc2007_transfer(priv,
+                           (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z2POS));
 
-  (void)tsc2007_transfer(tsc, (TSC2007_CMD_12BIT | TSC2007_CMD_PWRDN_IRQEN));
+      /* Power down ADC and enable PENIRQ */
+
+     (void)tsc2007_transfer(priv,
+                           (TSC2007_CMD_12BIT | TSC2007_CMD_PWRDN_IRQEN));
+
+      /* Now calculate the pressure using the first method, reduced to:
+       *
+       * Rtouch = X * Rxplate *(Z2 - Z1) * / Z1 / 4096
+       */
+
+      if (z1 == 0)
+        {
+          idbg("Z1 zero\n");
+          goto errout;
+        }
+
+      pressure = (x * config->rxplate * (z2 - z1)) / z1;
+      pressure = (pressure + 2048) >> 12;
+
+      ivdbg("Position: (%d,%4d) pressure: %u z1/2: (%d,%d)\n"
+            x, y, pressure, z1, z2);
+
+      /* Ignore out of range caculcations */
+
+      if (pressure > 0x0fff)
+        {
+          idbg("Dropped out-of-range pressure: %d\n", pressure);
+          goto errout;
+        }
+
+      /* Save the measurements */
+
+      priv->sample.x        = x;
+      priv->sample.y        = y;
+      priv->sample.pressure = pressure;
+    }
+
+  /* Note the availability of new measurements */
+
+  priv->sample.pendown = pendown;
+  priv->penchange      = true;
+
+  /* Notify any waiters that nes TSC2007 data is available */
+
+  tsc2007_notify(priv);
+
+  /* Exit, re-enabling TSC2007 interrupts */
+
+errout:
+  config->enable(config, true);
 }
 
 /****************************************************************************
@@ -280,8 +575,49 @@ static void tsc2007_sample(FAR struct tsc2007_dev_s *tsc,
 
 static int tsc2007_interrupt(int irq, FAR void *context)
 {
-# warning "Missing logic"
-  return -ENOSYS;
+  FAR struct tsc2007_dev_s    *priv;
+  FAR struct tsc2007_config_s *config;
+  int                          ret;
+
+  /* Which TSC2007 device caused the interrupt? */
+
+#ifndef CONFIG_TSC2007_MULTIPLE
+  priv = &g_tsc2007;
+#else
+  for (priv = g_tsc2007list;
+       priv && priv->configs->irq != irq;
+       priv = priv->flink);
+
+  ASSERT(priv != NULL);
+#endif
+
+  /* Get a pointer the callbacks for convenience (and so the code is not so
+   * ugly).
+   */
+
+  config = priv->config;
+  DEBUGASSERT(config != NULL);
+
+  /* Disable further interrupts */
+
+  config->enable(config, false);
+
+  /* Transfer processing to the worker thread.  Since TSC2007 interrupts are
+   * disabled while the work is pending, no special action should be required
+   * to protected the work queue.
+   */
+
+  DEBUGASSERT(priv->work.worker == NULL);
+  ret = work_queue(&priv->work, tsc2007_worker, priv, 0);
+  if (ret != 0)
+    {
+      illdbg("Failed to queue work: %d\n", ret);
+    }
+
+  /* Clear any pending interrupts and return success */
+
+  config->clear(config);
+  return OK;
 }
 
 /****************************************************************************
@@ -398,6 +734,7 @@ static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len
 {
   FAR struct inode         *inode;
   FAR struct tsc2007_dev_s *priv;
+  struct tsc2007_sample_s   sample;
   int                       ret;
 
   DEBUGASSERT(filep);
@@ -417,42 +754,42 @@ static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len
       return -EINTR;
     }
 
-#warning "Not implemented"
+  /* Try to read sample data. */
 
-  sem_post(&priv->devsem);
-  return -ENOSYS;
-}
-
-/****************************************************************************
- * Name: tsc2007_write
- ****************************************************************************/
+  ret = tsc2007_sample(priv, &sample);
+  if (ret < 0)
+    {
+      /* Sample data is not available now.  We would ave to wait to get
+       * receive sample data.  If the user has specified the O_NONBLOCK
+       * option, then just return an error.
+       */
 
-static ssize_t tsc2007_write(FAR struct file *filep, FAR const char *buffer, size_t len)
-{
-  FAR struct inode         *inode;
-  FAR struct tsc2007_dev_s *priv;
-  int                       ret;
+      if (filep->f_oflags & O_NONBLOCK)
+        {
+          ret = -EAGAIN;
+          goto errout;
+       }
 
-  DEBUGASSERT(filep);
-  inode = filep->f_inode;
+      /* Wait for sample data */
 
-  DEBUGASSERT(inode && inode->i_private);
-  priv  = (FAR struct tsc2007_dev_s *)inode->i_private;
+      ret = tsc2007_waitsample(priv, &sample);
+      if (ret < 0)
+        {
+          /* We might have been awakened by a signal */
 
-  /* Get exclusive access to the driver data structure */
+          goto errout;
+        }
+    }
 
-  ret = sem_wait(&priv->devsem);
-  if (ret < 0)
-    {
-      /* This should only happen if the wait was canceled by an signal */
+  /* In any event, we now have sampled TSC2007 data that we can report
+   * to the caller.
+   */
 
-      DEBUGASSERT(errno == EINTR);
-      return -EINTR;
-    }
+#warning "Missing logic"
 
-#warning "Not implemented"
+errout:
   sem_post(&priv->devsem);
-  return -ENOSYS;
+  return ret;
 }
 
 /****************************************************************************
@@ -533,6 +870,14 @@ static int tsc2007_poll(FAR struct file *filep, FAR struct pollfd *fds,
 
   if (setup)
     {
+      /* Ignore waits that do not include POLLIN */
+
+      if ((fds->revents & POLLIN) == 0)
+        {
+          ret = -EDEADLK;
+          goto errout;
+        }
+
       /* This is a request to set up the poll.  Find an available
        * slot for the poll structure reference
        */
@@ -545,7 +890,7 @@ static int tsc2007_poll(FAR struct file *filep, FAR struct pollfd *fds,
             {
               /* Bind the poll structure and this slot */
 
-              priv->fds[i]  = fds;
+              priv->fds[i] = fds;
               fds->priv    = &priv->fds[i];
               break;
             }
@@ -558,24 +903,19 @@ static int tsc2007_poll(FAR struct file *filep, FAR struct pollfd *fds,
           goto errout;
         }
 
-      /* Should immediately notify on any of the requested events? */
-#warning "Missing logic"
-
+      /* Should we immediately notify on any of the requested events? */
 
+      if (priv->penchange)
+        {
+          tsc2007_notify(priv);
+        }
     }
   else if (fds->priv)
     {
       /* This is a request to tear down the poll. */
 
       struct pollfd **slot = (struct pollfd **)fds->priv;
-
-#ifdef CONFIG_DEBUG
-      if (!slot)
-        {
-          ret              = -EIO;
-          goto errout;
-        }
-#endif
+      DEBUGASSERT(slot != NULL);
 
       /* Remove all memory of the poll setup */
 
@@ -621,20 +961,32 @@ int tsc2007_register(FAR struct i2c_dev_s *dev,
 {
   FAR struct tsc2007_dev_s *priv;
   char devname[DEV_NAMELEN];
+#ifdef CONFIG_TSC2007_MULTIPLE
+  irqstate_t flags;
+#endif
   int ret;
 
   ivdbg("dev: %p minor: %d\n", dev, minor);
+
+  /* Debug-only sanity checks */
+
   DEBUGASSERT(dev != NULL && config != NULL && minor > 0 && minor < 100);
   DEBUGASSERT((config->address & 0xfc) == 0x48);
+  DEBUGASSERT(config->attach != NULL && config->enable  != NULL
+              config->clear  != NULL && config->pendown != NULL);
 
   /* Create and initialize a TSC2007 device driver instance */
 
+#ifndef CONFIG_TSC2007_MULTIPLE
+  priv = &g_tsc2007;
+#else
   priv = (FAR struct tsc2007_dev_s *)kmalloc(sizeof(struct tsc2007_dev_s));
   if (!priv)
     {
       idbg("kmalloc(%d) failed\n", sizeof(struct tsc2007_dev_s));
       return -ENOMEM;
     }
+#endif
 
   /* Initialize the TSC2007 device driver instance */
 
@@ -642,6 +994,12 @@ int tsc2007_register(FAR struct i2c_dev_s *dev,
   priv->i2c    = dev;             /* Save the I2C device handle */
   priv->config = config;          /* Save the board configuration */
   sem_init(&priv->devsem,  0, 1); /* Initialize device structure semaphore */
+  sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */
+
+  /* Make sure that interrupts are disabled */
+
+  config->clear(config);
+  config->enable(config, false);
 
   /* Attach the interrupt handler */
 
@@ -667,6 +1025,7 @@ int tsc2007_register(FAR struct i2c_dev_s *dev,
 
   (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor);
   ivdbg("Registering %s\n", devname);
+
   ret = register_driver(devname, &tsc2007_fops, 0666, priv);
   if (ret < 0)
     {
@@ -674,18 +1033,37 @@ int tsc2007_register(FAR struct i2c_dev_s *dev,
       goto errout_with_priv;
     }
 
-  /* Enable the interrupt */
+  /* If multiple TSC2007 devices are supported, then we will need to add
+   * this new instance to a list of device instances so that it can be
+   * found by the interrupt handler based on the recieved IRQ number.
+   */
 
-  ret = config->enable(config, true);
-  if (ret < 0)
+#ifdef CONFIG_TSC2007_MULTIPLE
+  priv          = irqsave;
+  priv->flink   = g_tsc2007list;
+  g_tsc2007list = priv;
+  irqrestore(flags);
+#endif
+
+  /* Schedule work to perform the initial sampling and to set the data
+   * availability conditions.
+   */
+
+  ret = work_queue(&priv->work, tsc2007_worker, priv, 0);
+  if (ret != 0)
     {
-      idbg("Failed enable interrupt\n");
+      idbg("Failed to queue work: %d\n", ret);
       goto errout_with_priv;
     }
-  return ret;
+
+  /* And return success (?) */
+
+  return OK;
 
 errout_with_priv:
   sem_destroy(&priv->devsem);
+#ifdef CONFIG_TSC2007_MULTIPLE
   kfree(priv);
+#endif
   return ret;
 }
diff --git a/drivers/input/tsc2007.h b/drivers/input/tsc2007.h
index 0ece1627d8..067d6ba3b9 100644
--- a/drivers/input/tsc2007.h
+++ b/drivers/input/tsc2007.h
@@ -38,6 +38,11 @@
  *
  ********************************************************************************************/
 
+/* The TSC2007 is an analog interface circuit for a human interface touch screen device.
+ * All peripheral functions are controlled through the command byte and onboard state
+ * machines.
+ */
+
 #ifndef __DRIVERS_INPUT_TSC2007_H
 #define __DRIVERS_INPUT_TSC2007_H
 
@@ -96,16 +101,6 @@
  * Public Types
  ********************************************************************************************/
 
-/* This structure describes the sampled TSC2007 data */
-
-struct tsc2007_sample_s
-{
-  uint16_t x;    /* X position */
-  uint16_t y;    /* Y position */
-  uint16_t z1;   /* Z1 position */
-  uint16_t z2;   /* Z2 position */
-};
-
 /********************************************************************************************
  * Public Function Prototypes
  ********************************************************************************************/
diff --git a/drivers/wireless/cc1101/cc1101.c b/drivers/wireless/cc1101/cc1101.c
index b13a8bc6dd..e2fae96203 100755
--- a/drivers/wireless/cc1101/cc1101.c
+++ b/drivers/wireless/cc1101/cc1101.c
@@ -452,7 +452,8 @@ volatile int cc1101_interrupt = 0;
 
 int cc1101_eventcb(int irq, FAR void *context)
 {
-    cc1101_interrupt++;
+  cc1101_interrupt++;
+  return OK;
 }
 
 /****************************************************************************
diff --git a/include/nuttx/i2c.h b/include/nuttx/i2c.h
index 748b7cc607..56c1d81018 100644
--- a/include/nuttx/i2c.h
+++ b/include/nuttx/i2c.h
@@ -87,7 +87,7 @@
  *   i2c_dev_s instance and will be used with all transfers.  Required.
  *
  * Input Parameters:
- *   dev -       Device-specific state data
+ *   dev       - Device-specific state data
  *   frequency - The I2C frequency requested
  *
  * Returned Value:
@@ -105,9 +105,9 @@
  *   i2c_dev_s instance and will be used with all transfers.  Required.
  *
  * Input Parameters:
- *   dev -     Device-specific state data
+ *   dev     - Device-specific state data
  *   address - The I2C slave address
- *   nbits -   The number of address bits provided (7 or 10)
+ *   nbits   - The number of address bits provided (7 or 10)
  *
  * Returned Value:
  *   Returns OK on success; a negated errno on failure.
@@ -129,10 +129,10 @@
  *   to handle reads and writes from a master.
  *
  * Input Parameters:
- *   dev -     Device-specific state data
+ *   dev     - Device-specific state data
  *   address - Our own slave address; If it is 0x00, then the device driver
  *             listens to general call
- *   nbits -   The number of address bits provided (7 or 10)
+ *   nbits   - The number of address bits provided (7 or 10)
  *
  * Returned Value:
  *   OK on valid address and if the same address has not been assigned
@@ -152,7 +152,7 @@
  *   and pend until this write completes. Required.
  *
  * Input Parameters:
- *   dev -    Device-specific state data
+ *   dev    - Device-specific state data
  *   buffer - A pointer to the read-only buffer of data to be written to device
  *   buflen - The number of bytes to send from the buffer
  *
@@ -173,7 +173,7 @@
  *   and pend until this read completes. Required.
  *
  * Input Parameters:
- *   dev -   Device-specific state data
+ *   dev    - Device-specific state data
  *   buffer - A pointer to a buffer of data to receive the data from the device
  *   buflen - The requested number of bytes to be read
  *
@@ -193,7 +193,7 @@
  *   It provides a convenient wrapper to the transfer function.
  *
  * Input Parameters:
- *   dev -    Device-specific state data
+ *   dev     - Device-specific state data
  *   wbuffer - A pointer to the read-only buffer of data to be written to device
  *   wbuflen - The number of bytes to send from the buffer
  *   rbuffer - A pointer to a buffer of data to receive the data from the device
@@ -216,8 +216,8 @@
  *   will be serialized and pend until this read completes. Optional.
  *
  * Input Parameters:
- *   dev -   Device-specific state data
- *   msgs - A pointer to a set of message descriptors
+ *   dev      - Device-specific state data
+ *   msgs     - A pointer to a set of message descriptors
  *   msgcount - The number of transfers to perform
  *
  * Returned Value:
@@ -261,10 +261,10 @@ struct i2c_ops_s
 
 struct i2c_msg_s
 {
-    uint16_t  addr;                  /* Slave address */
-    uint16_t  flags;                 /* See I2C_M_* definitions */
-    uint8_t  *buffer;
-    int       length;
+  uint16_t  addr;                  /* Slave address */
+  uint16_t  flags;                 /* See I2C_M_* definitions */
+  uint8_t  *buffer;
+  int       length;
 };
 
 /* I2C private data.  This structure only defines the initial fields of the
@@ -308,7 +308,6 @@ extern "C" {
 
 EXTERN FAR struct i2c_dev_s *up_i2cinitialize(int port);
 
-
 /****************************************************************************
  * Name: up_i2cuninitialize
  *
diff --git a/include/nuttx/input/tsc2007.h b/include/nuttx/input/tsc2007.h
index 10e5d778d2..8956c61b9e 100644
--- a/include/nuttx/input/tsc2007.h
+++ b/include/nuttx/input/tsc2007.h
@@ -38,6 +38,11 @@
  *
  ****************************************************************************/
 
+/* The TSC2007 is an analog interface circuit for a human interface touch
+ * screen device. All peripheral functions are controlled through the command
+ * byte and onboard state machines.
+ */
+
 #ifndef __INCLUDE_NUTTX_INPUT_TSC2007_H
 #define __INCLUDE_NUTTX_INPUT_TSC2007_H
 
@@ -85,7 +90,9 @@
  * of the TSB2007 and provides some board-specific hooks.
  *
  * Memory for this structure is provided by the caller.  It is not copied
- * by the driver and is presumed to persist while the driver is active.
+ * by the driver and is presumed to persist while the driver is active. The
+ * memory must be writable because, under certain circumstances, the driver
+ * may modify frequency or X plate resistance values.
  */
 
 struct tsc2007_config_s
@@ -93,15 +100,31 @@ struct tsc2007_config_s
   /* Device characterization */
 
   uint8_t  address;    /* 7-bit I2C address (only bits 0-6 used) */
-  uint16_t caldata;    /* Calibrated X plate resistance data */
+  uint16_t rxplate;    /* Calibrated X plate resistance */
   uint32_t frequency;  /* I2C frequency */
 
-  /* IRQ/GPIO access callbacks */
+  /* If multiple TSC2007 devices are supported, then an IRQ number must
+   * be provided for each so that their interrupts can be distinguished.
+   */
+
+#ifndef CONFIG_TSC2007_MULTIPLE
+  int      irq;        /* IRQ number received by interrupt handler. */
+#endif
+
+  /* IRQ/GPIO access callbacks.  These operations all hidden behind
+   * callbacks to isolate the TSC2007 driver from differences in GPIO
+   * interrupt handling by varying boards and MCUs.
+   *
+   * attach  - Attach the TSC2007 interrupt handler to the GPIO interrupt
+   * enable  - Enable or disable the GPIO interrupt
+   * clear   - Acknowledge/clear any pending GPIO interrupt
+   * pendown - Return the state of the pen down GPIO input
+   */
 
   int (*attach)(FAR struct tsc2007_config_s *state, xcpt_t isr);
-  int (*enable)(FAR struct tsc2007_config_s *state, bool enable);
-  int (*clear)(FAR struct tsc2007_config_s *state);
-  int (*pendown)(FAR struct tsc2007_config_s *state);
+  void (*enable)(FAR struct tsc2007_config_s *state, bool enable);
+  void (*clear)(FAR struct tsc2007_config_s *state);
+  bool (*pendown)(FAR struct tsc2007_config_s *state);
 };
 
 /****************************************************************************
diff --git a/include/nuttx/wqueue.h b/include/nuttx/wqueue.h
index 2e4cd3e4eb..5f5fecef89 100755
--- a/include/nuttx/wqueue.h
+++ b/include/nuttx/wqueue.h
@@ -1,7 +1,7 @@
 /****************************************************************************
  * include/nuttx/wqueue.h
  *
- *   Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ *   Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <spudmonkey@racsa.co.cr>
  *
  * Redistribution and use in source and binary forms, with or without
-- 
GitLab