summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-07-30 17:41:22 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-07-30 17:41:22 +0000
commitb11b18fe1dcd3531625035d07322a263f4891e1f (patch)
treeaf0b6f5a27b11ffafbe6616cb253ef25d16d791b
parent291ccd2db69524176b349100a5710e451039a8ec (diff)
downloadnuttx-b11b18fe1dcd3531625035d07322a263f4891e1f.tar.gz
nuttx-b11b18fe1dcd3531625035d07322a263f4891e1f.tar.bz2
nuttx-b11b18fe1dcd3531625035d07322a263f4891e1f.zip
Completes first cut of TSC2007 driver
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3831 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog3
-rw-r--r--nuttx/drivers/input/tsc2007.c212
-rw-r--r--nuttx/include/nuttx/i2c.h4
-rw-r--r--nuttx/include/nuttx/input/tsc2007.h2
-rw-r--r--nuttx/include/nuttx/ioctl.h6
5 files changed, 190 insertions, 37 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index ea4a769a7..0650dac62 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -1955,4 +1955,7 @@
* graphics/nxfonts/nxfonts_*.h: Add serveral more new fonts
* arch/z80/src/ez80/ez80_serial.c: Fix some errors in serial driver
setup for UART1 (submitted by Paul Osmialowski).
+ * drivers/input/tsc2007.c and include/nuttx/input/*: Add a generic NuttX
+ touchscreen interface. Add a driver for the TI TSC2007 touchscreen
+ controller.
diff --git a/nuttx/drivers/input/tsc2007.c b/nuttx/drivers/input/tsc2007.c
index 7af6711bc..e79bb3568 100644
--- a/nuttx/drivers/input/tsc2007.c
+++ b/nuttx/drivers/input/tsc2007.c
@@ -67,6 +67,8 @@
#include <nuttx/fs.h>
#include <nuttx/i2c.h>
#include <nuttx/wqueue.h>
+
+#include <nuttx/input/touchscreen.h>
#include <nuttx/input/tsc2007.h>
#include "tsc2007.h"
@@ -74,6 +76,13 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+/* Configuration ************************************************************/
+/* Reference counting is partially implemented, but not needed in the
+ * current design.
+ */
+
+#undef CONFIG_TSC2007_REFCNT
+
/* Driver support ***********************************************************/
/* This format is used to construct the /dev/skel[n] device driver path. It
* defined here so that it will be used consistently in all places.
@@ -85,11 +94,22 @@
/****************************************************************************
* Private Types
****************************************************************************/
+
+/* This describes the state of one contact */
+
+enum tsc2007_contact_3
+{
+ CONTACT_NONE = 0, /* No contact */
+ CONTACT_DOWN, /* First contact */
+ CONTACT_MOVE, /* Same contact, possibly different position */
+ CONTACT_UP, /* Contact lost */
+};
+
/* This structure describes the results of one TSC2007 sample */
struct tsc2007_sample_s
{
- bool pendown; /* Pen down state */
+ uint8_t contact; /* Contact state (see enum tsc2007_contact_e) */
uint16_t x; /* Measured X position */
uint16_t y; /* Measured Y position */
uint16_t pressure; /* Calculated pressure */
@@ -102,8 +122,11 @@ struct tsc2007_dev_s
#ifdef CONFIG_TSC2007_MULTIPLE
FAR struct tsc2007_dev_s *flink; /* Supports a singly linked list of drivers */
#endif
+#ifdef CONFIG_TSC2007_REFCNT
uint8_t crefs; /* Number of times the device has been opened */
+#endif
uint8_t nwaiters; /* Number of threads waiting for TSC2007 data */
+ uint8_t id; /* Current touch point ID */
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 */
@@ -111,7 +134,7 @@ struct tsc2007_dev_s
FAR struct tsc2007_config_s *config; /* Board configuration data */
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 */
+ struct tsc2007_sample_s sample; /* Last sampled touch point data */
/* The following is a list if poll structures of threads waiting for
* driver events. The 'struct pollfd' reference for each open is also
@@ -251,6 +274,23 @@ static int tsc2007_sample(FAR struct tsc2007_dev_s *priv,
*/
memcpy(sample, &priv->sample, sizeof(struct tsc2007_sample_s ));
+
+ /* Now manage state transitions */
+
+ if (sample->contact == CONTACT_UP)
+ {
+ /* Next.. no contract. Increment the ID so that next contact will be unique */
+
+ priv->sample.contact = CONTACT_NONE;
+ priv->id++;
+ }
+ else if (sample->contact == CONTACT_DOWN)
+ {
+ /* First report -- next report will be a movement */
+
+ priv->sample.contact = CONTACT_MOVE;
+ }
+
priv->penchange = false;
ret = OK;
}
@@ -455,9 +495,11 @@ static void tsc2007_worker(FAR void *arg)
if (!pendown)
{
- /* Ignore the interrupt if the pen was already down */
+ /* Ignore the interrupt if the pen was already down (CONTACT_NONE == pen up and
+ * already reported. CONTACT_UP == pen up, but not reported)
+ */
- if (!priv->sample.pendown)
+ if (priv->sample.contact == CONTACT_NONE)
{
goto errout;
}
@@ -556,8 +598,31 @@ static void tsc2007_worker(FAR void *arg)
/* Note the availability of new measurements */
- priv->sample.pendown = pendown;
- priv->penchange = true;
+ if (pendown)
+ {
+ /* If this is the first (acknowledged) pend down report, then report
+ * this as the first contact. If contact == CONTACT_DOWN, it will be
+ * set to set to CONTACT_MOVE after the contact is first sampled.
+ */
+
+ if (priv->sample.contact != CONTACT_MOVE)
+ {
+ /* First contact */
+
+ priv->sample.contact = CONTACT_DOWN;
+ }
+ }
+ else /* if (priv->sample.contact != CONTACT_NONE) */
+ {
+ /* The pen is up. NOTE: We know from a previous test, that this is a
+ * loss of contact condition. This will be changed to CONTACT_NONE
+ * after the loss of contact is sampled.
+ */
+
+ priv->sample.contact = CONTACT_UP;
+ }
+
+ priv->penchange = true;
/* Notify any waiters that nes TSC2007 data is available */
@@ -626,6 +691,7 @@ static int tsc2007_interrupt(int irq, FAR void *context)
static int tsc2007_open(FAR struct file *filep)
{
+#ifdef CONFIG_TSC2007_REFCNT
FAR struct inode *inode;
FAR struct tsc2007_dev_s *priv;
uint8_t tmp;
@@ -659,17 +725,9 @@ static int tsc2007_open(FAR struct file *filep)
goto errout_with_sem;
}
- /* Check if this is the first time that the driver has been opened. */
-
- if (tmp == 1)
- {
- irqstate_t flags = irqsave();
-
- /* Perform one time hardware initialization */
-
-#warning "Missing logic"
- irqrestore(flags);
- }
+ /* When the reference increments to 1, this is the first open event
+ * on the driver.. and an opportunity to do any one-time initialization.
+ */
/* Save the new open count on success */
@@ -678,6 +736,9 @@ static int tsc2007_open(FAR struct file *filep)
errout_with_sem:
sem_post(&priv->devsem);
return ret;
+#else
+ return OK;
+#endif
}
/****************************************************************************
@@ -686,6 +747,7 @@ errout_with_sem:
static int tsc2007_close(FAR struct file *filep)
{
+#ifdef CONFIG_TSC2007_REFCNT
FAR struct inode *inode;
FAR struct tsc2007_dev_s *priv;
int ret;
@@ -707,22 +769,18 @@ static int tsc2007_close(FAR struct file *filep)
return -EINTR;
}
- /* Decrement the reference count unless it would decrement to zero */
- if (priv->crefs > 1)
+ /* Decrement the reference count unless it would decrement a negative
+ * value. When the count decrements to zero, there are no further
+ * open references to the driver.
+ */
+
+ if (priv->crefs >= 1)
{
priv->crefs--;
- sem_post(&priv->devsem);
- return OK;
}
- /* There are no more references to the port */
-
- priv->crefs = 0;
-
- /* Perform driver teardown */
-#warning "Missing logic"
-
sem_post(&priv->devsem);
+#endif
return OK;
}
@@ -732,10 +790,11 @@ static int tsc2007_close(FAR struct file *filep)
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;
+ FAR struct inode *inode;
+ FAR struct tsc2007_dev_s *priv;
+ FAR struct touch_sample_s *report;
+ struct tsc2007_sample_s sample;
+ int ret;
DEBUGASSERT(filep);
inode = filep->f_inode;
@@ -743,6 +802,19 @@ static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len
DEBUGASSERT(inode && inode->i_private);
priv = (FAR struct tsc2007_dev_s *)inode->i_private;
+ /* Verify that the caller has provided a buffer large enough to receive
+ * the touch data.
+ */
+
+ if (len < SIZEOF_TOUCH_SAMPLE_S(1))
+ {
+ /* We could provide logic to break up a touch report into segments and
+ * handle smaller reads... but why?
+ */
+
+ return -ENOSYS;
+ }
+
/* Get exclusive access to the driver data structure */
ret = sem_wait(&priv->devsem);
@@ -785,7 +857,36 @@ static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len
* to the caller.
*/
-#warning "Missing logic"
+ report = (FAR struct touch_sample_s *)buffer;
+ memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1));
+ report->npoints = 1;
+ report->point[0].id = priv->id;
+ report->point[0].x = sample.x;
+ report->point[0].y = sample.y;
+ report->point[0].pressure = sample.pressure;
+
+ /* Report the appropriate flags */
+
+ if (sample.contact == CONTACT_UP)
+ {
+ /* Pen is now up */
+
+ report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID |TOUCH_PRESSURE_VALID;
+ }
+ else if (sample.contact == CONTACT_DOWN)
+ {
+ /* First contact */
+
+ report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID |TOUCH_PRESSURE_VALID;
+ }
+ else /* if (sample->contact == CONTACT_MOVE) */
+ {
+ /* Movement of the same contact */
+
+ report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID |TOUCH_PRESSURE_VALID;
+ }
+
+ ret = SIZEOF_TOUCH_SAMPLE_S(1);
errout:
sem_post(&priv->devsem);
@@ -824,7 +925,37 @@ static int tsc2007_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
switch (cmd)
{
- /* Add support for ioctl commands here */
+ case TSIOC_SETCALIB: /* arg: Pointer to int calibration value */
+ {
+ FAR int *ptr = (FAR int *)((uintptr_t)arg);
+ DEBUGASSERT(priv->config != NULL && ptr != NULL);
+ priv->config->rxplate = *ptr;
+ }
+ break;
+
+ case TSIOC_GETCALIB: /* arg: Pointer to int calibration value */
+ {
+ FAR int *ptr = (FAR int *)((uintptr_t)arg);
+ DEBUGASSERT(priv->config != NULL && ptr != NULL);
+ *ptr = priv->config->rxplate;
+ }
+ break;
+
+ case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */
+ {
+ FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg);
+ DEBUGASSERT(priv->config != NULL && ptr != NULL);
+ priv->config->frequency = I2C_SETFREQUENCY(priv->i2c, *ptr);
+ }
+ break;
+
+ case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */
+ {
+ FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg);
+ DEBUGASSERT(priv->config != NULL && ptr != NULL);
+ *ptr = priv->config->frequency;
+ }
+ break;
default:
ret = -ENOTTY;
@@ -996,6 +1127,19 @@ int tsc2007_register(FAR struct i2c_dev_s *dev,
sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */
sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */
+ /* Set the I2C frequency (saving the actual frequency) */
+
+ config->frequency = I2C_SETFREQUENCY(dev, config->frequency);
+
+ /* Set the I2C address and address size */
+
+ ret = I2C_SETADDRESS(dev, config->address, 7);
+ if (ret < 0)
+ {
+ idbg("I2C_SETADDRESS failed: %d\n", ret);
+ goto errout_with_priv;
+ }
+
/* Make sure that interrupts are disabled */
config->clear(config);
diff --git a/nuttx/include/nuttx/i2c.h b/nuttx/include/nuttx/i2c.h
index 56c1d8101..d72b54b29 100644
--- a/nuttx/include/nuttx/i2c.h
+++ b/nuttx/include/nuttx/i2c.h
@@ -114,7 +114,7 @@
*
****************************************************************************/
-#define I2C_SETADDRESS(d,f,b) ((d)->ops->setaddress(d,f,b))
+#define I2C_SETADDRESS(d,a,n) ((d)->ops->setaddress(d,a,n))
/****************************************************************************
* Name: I2C_SETOWNADDRESS
@@ -140,7 +140,7 @@
*
****************************************************************************/
-#define I2C_SETOWNADDRESS(d,f,b) ((d)->ops->setownaddress(d,f,b))
+#define I2C_SETOWNADDRESS(d,a,n) ((d)->ops->setownaddress(d,a,n))
/****************************************************************************
* Name: I2C_WRITE
diff --git a/nuttx/include/nuttx/input/tsc2007.h b/nuttx/include/nuttx/input/tsc2007.h
index 8956c61b9..449b46b22 100644
--- a/nuttx/include/nuttx/input/tsc2007.h
+++ b/nuttx/include/nuttx/input/tsc2007.h
@@ -121,7 +121,7 @@ struct tsc2007_config_s
* pendown - Return the state of the pen down GPIO input
*/
- int (*attach)(FAR struct tsc2007_config_s *state, xcpt_t isr);
+ int (*attach)(FAR struct tsc2007_config_s *state, xcpt_t isr);
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/nuttx/include/nuttx/ioctl.h b/nuttx/include/nuttx/ioctl.h
index a13518a7a..0ce363f24 100644
--- a/nuttx/include/nuttx/ioctl.h
+++ b/nuttx/include/nuttx/ioctl.h
@@ -59,6 +59,7 @@
#define _MTDIOCBASE (0x8a00) /* MTD ioctl commands */
#define _SIOCBASE (0x8b00) /* Socket ioctl commands */
#define _ARPBASE (0x8c00) /* ARP ioctl commands */
+#define _TSBASE (0x8d00) /* Touchscreen ioctl commands */
/* Macros used to manage ioctl commands */
@@ -160,6 +161,11 @@
#define _ARPIOCVALID(c) (_IOC_TYPE(c)==_ARPBASE)
#define _ARPIOC(nr) _IOC(_ARPBASE,nr)
+/* NuttX ARP touchscrren ioctl definitions (see nuttx/input/touchscreen.h) **/
+
+#define _TSIOCVALID(c) (_IOC_TYPE(c)==_TSBASE)
+#define _TSIOC(nr) _IOC(_TSBASE,nr)
+
/****************************************************************************
* Public Type Definitions
****************************************************************************/