mirror of
https://github.com/apache/nuttx.git
synced 2026-09-28 03:09:13 +08:00
SAMA5 touchscreen and ADC: A little more progress
This commit is contained in:
@@ -5683,7 +5683,7 @@
|
|||||||
no serial driver) (from Alan Carvalho de Assis, 2013-9-30).
|
no serial driver) (from Alan Carvalho de Assis, 2013-9-30).
|
||||||
* configs/freedom-kl25z/minnsh: A new configuration that is
|
* configs/freedom-kl25z/minnsh: A new configuration that is
|
||||||
an experiement to see how small we can get the NuttX footprint.
|
an experiement to see how small we can get the NuttX footprint.
|
||||||
From Carvalho de Assis. (2013-9-30).
|
From Alan Carvalho de Assis. (2013-9-30).
|
||||||
* net/net_sendfile: The high performance sendfile logic is
|
* net/net_sendfile: The high performance sendfile logic is
|
||||||
now functional. From Max Holtzberg (2013-9-30).
|
now functional. From Max Holtzberg (2013-9-30).
|
||||||
* tools/define.sh: 'cut' long because as it once did. Script
|
* tools/define.sh: 'cut' long because as it once did. Script
|
||||||
|
|||||||
+205
-84
@@ -57,6 +57,7 @@
|
|||||||
|
|
||||||
#include "chip.h"
|
#include "chip.h"
|
||||||
#include "chip/sam_adc.h"
|
#include "chip/sam_adc.h"
|
||||||
|
#include "sam_dmac.h"
|
||||||
#include "sam_adc.h"
|
#include "sam_adc.h"
|
||||||
|
|
||||||
#if defined(CONFIG_SAMA5_ADC)
|
#if defined(CONFIG_SAMA5_ADC)
|
||||||
@@ -123,6 +124,19 @@
|
|||||||
SAMA5_CHAN6_ENABLE || SAMA5_CHAN7_ENABLE || SAMA5_CHAN8_ENABLE || \
|
SAMA5_CHAN6_ENABLE || SAMA5_CHAN7_ENABLE || SAMA5_CHAN8_ENABLE || \
|
||||||
SAMA5_CHAN9_ENABLE || SAMA5_CHAN10_ENABLE || SAMA5_CHAN11_ENABLE)
|
SAMA5_CHAN9_ENABLE || SAMA5_CHAN10_ENABLE || SAMA5_CHAN11_ENABLE)
|
||||||
|
|
||||||
|
/* DMA configuration flags */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_ADC_DMA
|
||||||
|
# define DMA_FLAGS \
|
||||||
|
DMACH_FLAG_FIFOCFG_LARGEST | \
|
||||||
|
((SAM_IRQ_ADC << DMACH_FLAG_PERIPHPID_SHIFT) | DMACH_FLAG_PERIPHAHB_AHB_IF2 | \
|
||||||
|
DMACH_FLAG_PERIPHH2SEL | DMACH_FLAG_PERIPHISPERIPH | \
|
||||||
|
DMACH_FLAG_PERIPHWIDTH_16BITS | DMACH_FLAG_PERIPHCHUNKSIZE_1 | \
|
||||||
|
((0x3f) << DMACH_FLAG_MEMPID_SHIFT) | DMACH_FLAG_MEMAHB_AHB_IF0 | \
|
||||||
|
DMACH_FLAG_MEMWIDTH_16BITS | DMACH_FLAG_MEMINCREMENT | \
|
||||||
|
DMACH_FLAG_MEMCHUNKSIZE_1)
|
||||||
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -133,6 +147,10 @@ struct sam_adc_s
|
|||||||
{
|
{
|
||||||
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
||||||
struct adc_dev_s dev; /* The external via of the ADC device */
|
struct adc_dev_s dev; /* The external via of the ADC device */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_ADC_DMA
|
||||||
|
DMA_HANDLE dma; /* Handle for DMA channel */
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug stuff */
|
/* Debug stuff */
|
||||||
@@ -155,6 +173,14 @@ static bool sam_adc_checkreg(struct sam_adc_s *priv, bool wr,
|
|||||||
uint32_t regval, uintptr_t address);
|
uint32_t regval, uintptr_t address);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* DMA helper functions */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_ADC_DMA
|
||||||
|
static void sam_adc_dmacallback(DMA_HANDLE handle, void *arg, int result);
|
||||||
|
static int sam_adc_dmasetup(struct sam_adc_s *priv, FAR uint8_t *buffer,
|
||||||
|
size_t buflen)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* ADC interrupt handling */
|
/* ADC interrupt handling */
|
||||||
|
|
||||||
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
||||||
@@ -207,6 +233,9 @@ static struct adc_dev_s g_adcdev =
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Register Operations
|
||||||
|
****************************************************************************/
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: sam_adc_checkreg
|
* Name: sam_adc_checkreg
|
||||||
*
|
*
|
||||||
@@ -263,6 +292,169 @@ static bool sam_adc_checkreg(struct sam_adc_s *priv, bool wr,
|
|||||||
|
|
||||||
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* DMA Helpers
|
||||||
|
****************************************************************************/
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sam_adc_dmacallback
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Called when HSMCI DMA completes
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_ADC_DMA
|
||||||
|
static void sam_adc_dmacallback(DMA_HANDLE handle, void *arg, int result)
|
||||||
|
{
|
||||||
|
struct sam_dev_s *priv = (struct sam_dev_s *)arg;
|
||||||
|
#warning Missing logic
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sam_adc_dmasetup
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Setup to perform a read DMA. If the processor supports a data cache,
|
||||||
|
* then this method will also make sure that the contents of the DMA memory
|
||||||
|
* and the data cache are coherent. For read transfers this may mean
|
||||||
|
* invalidating the data cache.
|
||||||
|
*
|
||||||
|
* Input Parameters:
|
||||||
|
* dev - An instance of the SDIO device interface
|
||||||
|
* buffer - The memory to DMA from
|
||||||
|
* buflen - The size of the DMA transfer in bytes
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* OK on success; a negated errno on failure
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_ADC_DMA
|
||||||
|
static int sam_adc_dmasetup(FAR struct sdio_dev_s *dev, FAR uint8_t *buffer,
|
||||||
|
size_t buflen)
|
||||||
|
{
|
||||||
|
struct sam_dev_s *priv = (struct sam_dev_s *)dev;
|
||||||
|
uint32_t paddr;
|
||||||
|
uint32_t maddr;
|
||||||
|
|
||||||
|
DEBUGASSERT(priv != NULL && buffer != NULL && buflen > 0);
|
||||||
|
DEBUGASSERT(((uint32_t)buffer & 3) == 0);
|
||||||
|
|
||||||
|
/* Physical address of the ADC LCDR register and of the buffer location in
|
||||||
|
* RAM.
|
||||||
|
*/
|
||||||
|
|
||||||
|
paddr = sam_physregaddr(SAM_ADC_LCDR);
|
||||||
|
maddr = sam_physramaddr((uintptr_t)buffer);
|
||||||
|
|
||||||
|
/* Configure the RX DMA */
|
||||||
|
|
||||||
|
sam_dmarxsetup(priv->dma, paddr, maddr, buflen);
|
||||||
|
|
||||||
|
/* Enable DMA handshaking */
|
||||||
|
#warning Missing logic
|
||||||
|
|
||||||
|
/* Start the DMA */
|
||||||
|
|
||||||
|
sam_dmastart(priv->dma, sam_adc_dmacallback, priv);
|
||||||
|
|
||||||
|
/* Configure DMA-related interrupts */
|
||||||
|
#warning Missing loic
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* ADC interrupt handling
|
||||||
|
****************************************************************************/
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sam_adc_endconversion
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* End of conversion interrupt handler
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void sam_adc_endconversion(struct sam_adc_s *priv, uint32_t pending)
|
||||||
|
{
|
||||||
|
uint32_t regval;
|
||||||
|
int chan;
|
||||||
|
|
||||||
|
/* Check for the end of conversion event on each channel */
|
||||||
|
|
||||||
|
for (chan = 0; chan < SAM_ADC_NCHANNELS && pending != 0; chan++)
|
||||||
|
{
|
||||||
|
uint32_t bit = ADC_INT_EOC(chan);
|
||||||
|
if ((pending & bit) != 0)
|
||||||
|
{
|
||||||
|
/* Read the ADC sample and pass it to the upper half */
|
||||||
|
|
||||||
|
regval = sam_adc_getreg(priv, SAM_ADC_CDR(chan));
|
||||||
|
ret = adc_receive(&priv->dev, chan, regval & ADC_CDR_DATA_MASK);
|
||||||
|
pending &= ~bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* SAMA5_ADC_HAVE_CHANNELS */
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sam_adc_interrupt
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* ADC interrupt handler
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int sam_adc_interrupt(int irq, void *context)
|
||||||
|
{
|
||||||
|
struct sam_adc_s *priv = (struct sam_adc_s *)g_adcdev.ad_priv;
|
||||||
|
uint32_t isr;
|
||||||
|
uint32_t imr;
|
||||||
|
uint32_t pending;
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
|
/* Get the set of unmasked, pending ADC interrupts */
|
||||||
|
|
||||||
|
isr = sam_adc_getreg(priv, SAM_ADC_ISR);
|
||||||
|
imr = sam_adc_getreg(priv, SAM_ADC_IMR);
|
||||||
|
pending = isr & imr;
|
||||||
|
|
||||||
|
/* Handle pending touchscreen interrupts */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_TOUCHSCREEN
|
||||||
|
if ((pending & ADC_TSD_INTS) != 0)
|
||||||
|
{
|
||||||
|
/* Let the touchscreen handle its interrupts */
|
||||||
|
|
||||||
|
sam_tsd_interrupt(pending);
|
||||||
|
pending &= ~ADC_TSD_INTS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
||||||
|
/* Check for end-of-conversion interrupts */
|
||||||
|
|
||||||
|
if ((pending & ADC_INT_EOCALL) != 0)
|
||||||
|
{
|
||||||
|
/* Let the touchscreen handle its interrupts */
|
||||||
|
|
||||||
|
sam_adc_endconversion(pending);
|
||||||
|
pending &= ~ADC_INT_EOCALL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Make sure that all interrupts were handled */
|
||||||
|
|
||||||
|
DEBUGASSERT(pending == 0);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* ADC methods
|
||||||
|
****************************************************************************/
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: sam_adc_reset
|
* Name: sam_adc_reset
|
||||||
*
|
*
|
||||||
@@ -278,6 +470,12 @@ static void sam_adc_reset(struct adc_dev_s *dev)
|
|||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_ADC_DMA
|
||||||
|
/* Stop any ongoing DMA */
|
||||||
|
|
||||||
|
sam_dmastop(priv->dma);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Reset the ADC controller */
|
/* Reset the ADC controller */
|
||||||
|
|
||||||
flags = irqsave();
|
flags = irqsave();
|
||||||
@@ -388,90 +586,6 @@ static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg)
|
|||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: sam_adc_endconversion
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* End of conversion interrupt handler
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void sam_adc_endconversion(struct sam_adc_s *priv, uint32_t pending)
|
|
||||||
{
|
|
||||||
uint32_t regval;
|
|
||||||
int chan;
|
|
||||||
|
|
||||||
/* Check for the end of conversion event on each channel */
|
|
||||||
|
|
||||||
for (chan = 0; chan < SAM_ADC_NCHANNELS && pending != 0; chan++)
|
|
||||||
{
|
|
||||||
uint32_t bit = ADC_INT_EOC(chan);
|
|
||||||
if ((pending & bit) != 0)
|
|
||||||
{
|
|
||||||
/* Read the ADC sample and pass it to the upper half */
|
|
||||||
|
|
||||||
regval = sam_adc_getreg(priv, SAM_ADC_CDR(chan));
|
|
||||||
ret = adc_receive(&priv->dev, chan, regval & ADC_CDR_DATA_MASK);
|
|
||||||
pending &= ~bit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* SAMA5_ADC_HAVE_CHANNELS */
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: sam_adc_interrupt
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* ADC interrupt handler
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int sam_adc_interrupt(int irq, void *context)
|
|
||||||
{
|
|
||||||
struct sam_adc_s *priv = (struct sam_adc_s *)g_adcdev.ad_priv;
|
|
||||||
uint32_t regval;
|
|
||||||
struct sam_adc_s *priv = &g_adcpriv;
|
|
||||||
uint32_t isr;
|
|
||||||
uint32_t imr;
|
|
||||||
uint32_t pending;
|
|
||||||
|
|
||||||
/* Get the set of unmasked, pending ADC interrupts */
|
|
||||||
|
|
||||||
isr = sam_adc_getreg(priv, SAM_ADC_ISR);
|
|
||||||
imr = sam_adc_getreg(priv, SAM_ADC_IMR);
|
|
||||||
pending = isr & imr;
|
|
||||||
|
|
||||||
/* Handle pending touchscreen interrupts */
|
|
||||||
|
|
||||||
#ifdef CONFIG_SAMA5_TOUCHSCREEN
|
|
||||||
if ((pending & ADC_TSD_INTS) != 0)
|
|
||||||
{
|
|
||||||
/* Let the touchscreen handle its interrupts */
|
|
||||||
|
|
||||||
sam_tsd_interrupt(pending);
|
|
||||||
pending &= ~ADC_TSD_INTS;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
|
||||||
/* Check for end-of-conversion interrupts */
|
|
||||||
|
|
||||||
if ((pending & ADC_INT_EOCALL) != 0)
|
|
||||||
{
|
|
||||||
/* Let the touchscreen handle its interrupts */
|
|
||||||
|
|
||||||
sam_adc_endconversion(pending);
|
|
||||||
pending &= ~ADC_INT_EOCALL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Make sure that all interrupts were handled */
|
|
||||||
|
|
||||||
DEBUGASSERT(pending == 0);
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -535,6 +649,13 @@ struct adc_dev_s *sam_adc_initialize(void)
|
|||||||
sam_configpio(PIO_ADC_TRG);
|
sam_configpio(PIO_ADC_TRG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SAMA5_ADC_DMA
|
||||||
|
/* Allocate a DMA channel */
|
||||||
|
|
||||||
|
priv->dma = sam_dmachannel(dmac, DMA_FLAGS);
|
||||||
|
DEBUGASSERT(priv->dma);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Reset the ADC controller */
|
/* Reset the ADC controller */
|
||||||
|
|
||||||
sam_adc_putreg(priv, SAM_ADC_CR, ADC_CR_SWRST);
|
sam_adc_putreg(priv, SAM_ADC_CR, ADC_CR_SWRST);
|
||||||
|
|||||||
@@ -67,12 +67,12 @@
|
|||||||
* defined here so that it will be used consistently in all places.
|
* defined here so that it will be used consistently in all places.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define DEV_FORMAT "/dev/input%d"
|
#define DEV_FORMAT "/dev/input%d"
|
||||||
#define DEV_NAMELEN 16
|
#define DEV_NAMELEN 16
|
||||||
|
|
||||||
/* Poll the pen position while the pen is down at this rate (50MS): */
|
/* Poll the pen position while the pen is down at this rate (50MS): */
|
||||||
|
|
||||||
#define TSD_WDOG_DELAY ((50 + (MSEC_PER_TICK-1))/ MSEC_PER_TICK)
|
#define TSD_WDOG_DELAY ((50 + (MSEC_PER_TICK-1))/ MSEC_PER_TICK)
|
||||||
|
|
||||||
/* This is a value for the threshold that guantees a big difference on the
|
/* This is a value for the threshold that guantees a big difference on the
|
||||||
* first pendown (but can't overflow).
|
* first pendown (but can't overflow).
|
||||||
@@ -80,13 +80,36 @@
|
|||||||
|
|
||||||
#define INVALID_THRESHOLD 0x1000
|
#define INVALID_THRESHOLD 0x1000
|
||||||
|
|
||||||
|
/* Touchscreen interrupt event sets
|
||||||
|
*
|
||||||
|
* ADC_INT_XRDY TS Measure XPOS Ready Interrupt
|
||||||
|
* ADC_INT_YRDY TS Measure YPOS Ready Interrupt
|
||||||
|
* ADC_INT_PRDY TS Measure Pressure Ready Interrupt
|
||||||
|
* ADC_INT_PEN Pen Contact Interrupt
|
||||||
|
* ADC_INT_NOPEN No Pen Contact Interrupt
|
||||||
|
* ADC_SR_PENS Pen detect Status (Not an interrupt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ADC_TSD_CMNINTS (ADC_INT_XRDY | ADC_INT_YRDY | ADC_INT_PRDY | ADC_INT_NOPEN)
|
||||||
|
#define ADC_TSD_ALLINTS (ADC_TSD_CMNINTS | ADC_INT_PEN)
|
||||||
|
#define ADC_TSD_ALLSTATUS (ADC_TSD_ALLINTS | ADC_INT_PENS)
|
||||||
|
#define ADC_TSD_RELEASEINTS ADC_TSD_CMNINTS
|
||||||
|
|
||||||
|
/* Data ready/pen status bit definitions */
|
||||||
|
|
||||||
|
#define TSD_XREADY (1 << 0) /* X value is ready */
|
||||||
|
#define TSD_YREADY (1 << 1) /* Y value is ready */
|
||||||
|
#define TSD_PREADY (1 << 2) /* Pressure value is ready */
|
||||||
|
#define TSD_PENDOWN (1 << 3) /* Pen is down */
|
||||||
|
#define TSD_ALLREADY (TSD_XREADY | TSD_YREADY | TSD_PREADY)
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Types
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
/* This describes the state of one contact */
|
/* This describes the state of one contact */
|
||||||
|
|
||||||
enum sam_contact_3
|
enum sam_contact_e
|
||||||
{
|
{
|
||||||
CONTACT_NONE = 0, /* No contact */
|
CONTACT_NONE = 0, /* No contact */
|
||||||
CONTACT_DOWN, /* First contact */
|
CONTACT_DOWN, /* First contact */
|
||||||
@@ -107,13 +130,15 @@ struct sam_sample_s
|
|||||||
|
|
||||||
/* This structure describes the state of one touchscreen driver instance */
|
/* This structure describes the state of one touchscreen driver instance */
|
||||||
|
|
||||||
struct sam_dev_s
|
struct sam_tsd_s
|
||||||
{
|
{
|
||||||
uint8_t nwaiters; /* Number of threads waiting for touchscreen data */
|
uint8_t nwaiters; /* Number of threads waiting for touchscreen data */
|
||||||
uint8_t id; /* Current touch point ID */
|
uint8_t id; /* Current touch point ID */
|
||||||
|
uint8_t status; /* Data ready/pen status bit set */
|
||||||
volatile bool penchange; /* An unreported event is buffered */
|
volatile bool penchange; /* An unreported event is buffered */
|
||||||
uint16_t threshx; /* Thresholding X value */
|
uint16_t threshx; /* Thresholding X value */
|
||||||
uint16_t threshy; /* Thresholding Y value */
|
uint16_t threshy; /* Thresholding Y value */
|
||||||
|
volatile uint32_t pending; /* Pending interrupt set set */
|
||||||
sem_t devsem; /* Manages exclusive access to this structure */
|
sem_t devsem; /* Manages exclusive access to this structure */
|
||||||
sem_t waitsem; /* Used to wait for the availability of data */
|
sem_t waitsem; /* Used to wait for the availability of data */
|
||||||
|
|
||||||
@@ -138,22 +163,22 @@ struct sam_dev_s
|
|||||||
|
|
||||||
/* Interrupt bottom half logic and data sampling */
|
/* Interrupt bottom half logic and data sampling */
|
||||||
|
|
||||||
static void sam_notify(FAR struct sam_dev_s *priv);
|
static void sam_notify(struct sam_tsd_s *priv);
|
||||||
static int sam_sample(FAR struct sam_dev_s *priv,
|
static int sam_sample(struct sam_tsd_s *priv, struct sam_sample_s *sample);
|
||||||
FAR struct sam_sample_s *sample);
|
static int sam_waitsample(struct sam_tsd_s *priv,
|
||||||
static int sam_waitsample(FAR struct sam_dev_s *priv,
|
struct sam_sample_s *sample);
|
||||||
FAR struct sam_sample_s *sample);
|
static void sam_bottomhalf(void *arg);
|
||||||
static void sam_bottomhalf(FAR void *arg);
|
static int sam_schedule(struct sam_tsd_s *priv, uint32_t pending);
|
||||||
|
static void sam_wdog(int argc, uint32_t arg1, ...);
|
||||||
|
|
||||||
/* Character driver methods */
|
/* Character driver methods */
|
||||||
|
|
||||||
static int sam_open(FAR struct file *filep);
|
static int sam_open(struct file *filep);
|
||||||
static int sam_close(FAR struct file *filep);
|
static int sam_close(struct file *filep);
|
||||||
static ssize_t sam_read(FAR struct file *filep, FAR char *buffer,
|
static ssize_t sam_read(struct file *filep, char *buffer, size_t len);
|
||||||
size_t len);
|
static int sam_ioctl(struct file *filep, int cmd, unsigned long arg);
|
||||||
static int sam_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
|
||||||
#ifndef CONFIG_DISABLE_POLL
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
static int sam_poll(FAR struct file *filep, struct pollfd *fds, bool setup);
|
static int sam_poll(struct file *filep, struct pollfd *fds, bool setup);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -177,7 +202,7 @@ static const struct file_operations g_tsdops =
|
|||||||
|
|
||||||
/* The driver state structure is pre-allocated. */
|
/* The driver state structure is pre-allocated. */
|
||||||
|
|
||||||
static struct sam_dev_s g_tsd;
|
static struct sam_tsd_s g_tsd;
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
@@ -187,7 +212,7 @@ static struct sam_dev_s g_tsd;
|
|||||||
* Name: sam_notify
|
* Name: sam_notify
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void sam_notify(FAR struct sam_dev_s *priv)
|
static void sam_notify(struct sam_tsd_s *priv)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_DISABLE_POLL
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
int i;
|
int i;
|
||||||
@@ -230,8 +255,7 @@ static void sam_notify(FAR struct sam_dev_s *priv)
|
|||||||
* Name: sam_sample
|
* Name: sam_sample
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int sam_sample(FAR struct sam_dev_s *priv,
|
static int sam_sample(struct sam_tsd_s *priv, struct sam_sample_s *sample)
|
||||||
FAR struct sam_sample_s *sample)
|
|
||||||
{
|
{
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
int ret = -EAGAIN;
|
int ret = -EAGAIN;
|
||||||
@@ -284,8 +308,7 @@ static int sam_sample(FAR struct sam_dev_s *priv,
|
|||||||
* Name: sam_waitsample
|
* Name: sam_waitsample
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int sam_waitsample(FAR struct sam_dev_s *priv,
|
static int sam_waitsample(struct sam_tsd_s *priv, struct sam_sample_s *sample)
|
||||||
FAR struct sam_sample_s *sample)
|
|
||||||
{
|
{
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -361,58 +384,29 @@ errout:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: sam_schedule
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int sam_schedule(FAR struct sam_dev_s *priv)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Disable further touchscreen interrupts. Touchscreen interrupts will be
|
|
||||||
* re-enabled after the worker thread executes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sam_adc_putreg32(priv->dev, SAM_ADC_IDR, ADC_TSD_INTS);
|
|
||||||
|
|
||||||
/* Disable the watchdog timer. It will be re-enabled in the worker thread
|
|
||||||
* while the pen remains down.
|
|
||||||
*/
|
|
||||||
|
|
||||||
wd_cancel(priv->wdog);
|
|
||||||
|
|
||||||
/* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DEBUGASSERT(priv->work.worker == NULL);
|
|
||||||
ret = work_queue(HPWORK, &priv->work, sam_bottomhalf, priv, 0);
|
|
||||||
if (ret != 0)
|
|
||||||
{
|
|
||||||
illdbg("Failed to queue work: %d\n", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Name: sam_wdog
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static void sam_wdog(int argc, uint32_t arg1, ...)
|
|
||||||
{
|
|
||||||
FAR struct sam_dev_s *priv = (FAR struct sam_dev_s *)((uintptr_t)arg1);
|
|
||||||
(void)sam_schedule(priv);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: sam_bottomhalf
|
* Name: sam_bottomhalf
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function executes on the worker thread. It is scheduled by
|
||||||
|
* sam_tsd_interrupt whenever any interesting, enabled TSD event occurs.
|
||||||
|
* All TSD interrupts are disabled when this function runs. sam_bottomhalf
|
||||||
|
* will re-enable TSD interrupts when it completes processing all pending
|
||||||
|
* TSD events.
|
||||||
|
*
|
||||||
|
* Input Parameters
|
||||||
|
* arg - The touchscreen private data structure cast to (void *)
|
||||||
|
*
|
||||||
|
* Returned Value:
|
||||||
|
* None
|
||||||
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static void sam_bottomhalf(FAR void *arg)
|
static void sam_bottomhalf(void *arg)
|
||||||
{
|
{
|
||||||
FAR struct sam_dev_s *priv = (FAR struct sam_dev_s *)arg;
|
struct sam_tsd_s *priv = (struct sam_tsd_s *)arg;
|
||||||
|
uint32_t pending;
|
||||||
|
uint32_t regval;
|
||||||
uint16_t x;
|
uint16_t x;
|
||||||
uint16_t y;
|
uint16_t y;
|
||||||
uint16_t xdiff;
|
uint16_t xdiff;
|
||||||
@@ -428,6 +422,10 @@ static void sam_bottomhalf(FAR void *arg)
|
|||||||
|
|
||||||
wd_cancel(priv->wdog);
|
wd_cancel(priv->wdog);
|
||||||
|
|
||||||
|
/* Get the set of unmasked, pending ADC interrupts */
|
||||||
|
|
||||||
|
pending = priv->pending;
|
||||||
|
|
||||||
/* Get exclusive access to the driver data structure */
|
/* Get exclusive access to the driver data structure */
|
||||||
|
|
||||||
do
|
do
|
||||||
@@ -556,18 +554,81 @@ static void sam_bottomhalf(FAR void *arg)
|
|||||||
ignored:
|
ignored:
|
||||||
/* Re-enable touchscreen interrupts. */
|
/* Re-enable touchscreen interrupts. */
|
||||||
|
|
||||||
sam_adc_putreg32(priv->dev, SAM_ADC_IER, ADC_TSD_INTS);
|
sam_adc_putreg32(priv->dev, SAM_ADC_IER, ADC_TSD_ALLINTS);
|
||||||
|
|
||||||
/* Release our lock on the state structure */
|
/* Release our lock on the state structure */
|
||||||
|
|
||||||
sem_post(&priv->devsem);
|
sem_post(&priv->devsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sam_schedule
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static int sam_schedule(struct sam_tsd_s *priv, uint32_t pending)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Disable the watchdog timer. It will be re-enabled in the worker thread
|
||||||
|
* while the pen remains down.
|
||||||
|
*/
|
||||||
|
|
||||||
|
wd_cancel(priv->wdog);
|
||||||
|
|
||||||
|
/* Disable further touchscreen interrupts. Touchscreen interrupts will be
|
||||||
|
* re-enabled after the worker thread executes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sam_adc_putreg32(priv->dev, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(priv->work.worker == NULL);
|
||||||
|
ret = work_queue(HPWORK, &priv->work, sam_bottomhalf, priv, 0);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
illdbg("Failed to queue work: %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Name: sam_wdog
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* While the pen is pressed, pen position is periodically polled via a
|
||||||
|
* watchdog timer. This function handles that timer expiration.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static void sam_wdog(int argc, uint32_t arg1, ...)
|
||||||
|
{
|
||||||
|
struct sam_tsd_s *priv = (struct sam_tsd_s *)((uintptr_t)arg1);
|
||||||
|
uint32_t pending;
|
||||||
|
|
||||||
|
/* There should be no pending TSD interrupts, but we need to get the PENS
|
||||||
|
* status bit as a minimum.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pending = sam_adc_getreg(priv, SAM_ADC_ISR) & ADC_TSD_ALLSTATUS;
|
||||||
|
(void)sam_schedule(priv, pending);
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: sam_open
|
* Name: sam_open
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int sam_open(FAR struct file *filep)
|
static int sam_open(struct file *filep)
|
||||||
{
|
{
|
||||||
ivdbg("Opening\n");
|
ivdbg("Opening\n");
|
||||||
return OK;
|
return OK;
|
||||||
@@ -577,7 +638,7 @@ static int sam_open(FAR struct file *filep)
|
|||||||
* Name: sam_close
|
* Name: sam_close
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int sam_close(FAR struct file *filep)
|
static int sam_close(struct file *filep)
|
||||||
{
|
{
|
||||||
ivdbg("Closing\n");
|
ivdbg("Closing\n");
|
||||||
return OK;
|
return OK;
|
||||||
@@ -587,11 +648,11 @@ static int sam_close(FAR struct file *filep)
|
|||||||
* Name: sam_read
|
* Name: sam_read
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static ssize_t sam_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
static ssize_t sam_read(struct file *filep, char *buffer, size_t len)
|
||||||
{
|
{
|
||||||
FAR struct inode *inode;
|
struct inode *inode;
|
||||||
FAR struct sam_dev_s *priv;
|
struct sam_tsd_s *priv;
|
||||||
FAR struct touch_sample_s *report;
|
struct touch_sample_s *report;
|
||||||
struct sam_sample_s sample;
|
struct sam_sample_s sample;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -600,7 +661,7 @@ static ssize_t sam_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
|||||||
inode = filep->f_inode;
|
inode = filep->f_inode;
|
||||||
|
|
||||||
DEBUGASSERT(inode && inode->i_private);
|
DEBUGASSERT(inode && inode->i_private);
|
||||||
priv = (FAR struct sam_dev_s *)inode->i_private;
|
priv = (struct sam_tsd_s *)inode->i_private;
|
||||||
|
|
||||||
/* Verify that the caller has provided a buffer large enough to receive
|
/* Verify that the caller has provided a buffer large enough to receive
|
||||||
* the touch data.
|
* the touch data.
|
||||||
@@ -661,12 +722,12 @@ static ssize_t sam_read(FAR struct file *filep, FAR char *buffer, size_t len)
|
|||||||
* to the caller.
|
* to the caller.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
report = (FAR struct touch_sample_s *)buffer;
|
report = (struct touch_sample_s *)buffer;
|
||||||
memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1));
|
memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1));
|
||||||
report->npoints = 1;
|
report->npoints = 1;
|
||||||
report->point[0].id = sample.id;
|
report->point[0].id = sample.id;
|
||||||
report->point[0].x = sample.x;
|
report->point[0].x = sample.x;
|
||||||
report->point[0].y = sample.y;
|
report->point[0].y = sample.y;
|
||||||
|
|
||||||
/* Report the appropriate flags */
|
/* Report the appropriate flags */
|
||||||
|
|
||||||
@@ -716,18 +777,18 @@ errout:
|
|||||||
* Name:sam_ioctl
|
* Name:sam_ioctl
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int sam_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
static int sam_ioctl(struct file *filep, int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
FAR struct inode *inode;
|
struct inode *inode;
|
||||||
FAR struct sam_dev_s *priv;
|
struct sam_tsd_s *priv;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ivdbg("cmd: %d arg: %ld\n", cmd, arg);
|
ivdbg("cmd: %d arg: %ld\n", cmd, arg);
|
||||||
DEBUGASSERT(filep);
|
DEBUGASSERT(filep);
|
||||||
inode = filep->f_inode;
|
inode = filep->f_inode;
|
||||||
|
|
||||||
DEBUGASSERT(inode && inode->i_private);
|
DEBUGASSERT(inode && inode->i_private);
|
||||||
priv = (FAR struct sam_dev_s *)inode->i_private;
|
priv = (struct sam_tsd_s *)inode->i_private;
|
||||||
|
|
||||||
/* Get exclusive access to the driver data structure */
|
/* Get exclusive access to the driver data structure */
|
||||||
|
|
||||||
@@ -758,20 +819,19 @@ static int sam_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef CONFIG_DISABLE_POLL
|
#ifndef CONFIG_DISABLE_POLL
|
||||||
static int sam_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
static int sam_poll(struct file *filep, struct pollfd *fds, bool setup)
|
||||||
bool setup)
|
|
||||||
{
|
{
|
||||||
FAR struct inode *inode;
|
struct inode *inode;
|
||||||
FAR struct sam_dev_s *priv;
|
struct sam_tsd_s *priv;
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ivdbg("setup: %d\n", (int)setup);
|
ivdbg("setup: %d\n", (int)setup);
|
||||||
DEBUGASSERT(filep && fds);
|
DEBUGASSERT(filep && fds);
|
||||||
inode = filep->f_inode;
|
inode = filep->f_inode;
|
||||||
|
|
||||||
DEBUGASSERT(inode && inode->i_private);
|
DEBUGASSERT(inode && inode->i_private);
|
||||||
priv = (FAR struct sam_dev_s *)inode->i_private;
|
priv = (struct sam_tsd_s *)inode->i_private;
|
||||||
|
|
||||||
/* Are we setting up the poll? Or tearing it down? */
|
/* Are we setting up the poll? Or tearing it down? */
|
||||||
|
|
||||||
@@ -871,7 +931,7 @@ errout:
|
|||||||
|
|
||||||
int sam_tsd_register(struct adc_dev_s *dev, int minor)
|
int sam_tsd_register(struct adc_dev_s *dev, int minor)
|
||||||
{
|
{
|
||||||
struct sam_dev_s *priv = &g_tsd;
|
struct sam_tsd_s *priv = &g_tsd;
|
||||||
char devname[DEV_NAMELEN];
|
char devname[DEV_NAMELEN];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -883,7 +943,7 @@ int sam_tsd_register(struct adc_dev_s *dev, int minor)
|
|||||||
|
|
||||||
/* Initialize the touchscreen device driver instance */
|
/* Initialize the touchscreen device driver instance */
|
||||||
|
|
||||||
memset(priv, 0, sizeof(struct sam_dev_s));
|
memset(priv, 0, sizeof(struct sam_tsd_s));
|
||||||
priv->dev = dev; /* Save the ADC device handle */
|
priv->dev = dev; /* Save the ADC device handle */
|
||||||
priv->wdog = wd_create(); /* Create a watchdog timer */
|
priv->wdog = wd_create(); /* Create a watchdog timer */
|
||||||
priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */
|
priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */
|
||||||
@@ -941,29 +1001,43 @@ errout_with_priv:
|
|||||||
* Handles ADC interrupts associated with touchscreen channels
|
* Handles ADC interrupts associated with touchscreen channels
|
||||||
*
|
*
|
||||||
* Input parmeters:
|
* Input parmeters:
|
||||||
* None
|
* pending - Current set of pending interrupts being handled
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* None
|
* None
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
void sam_tsd_interrupt(void)
|
void sam_tsd_interrupt(uint32_t pending)
|
||||||
{
|
{
|
||||||
struct sam_dev_s *priv = &g_tsd;
|
struct sam_tsd_s *priv = &g_tsd;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Disable further touchscreen interrupts */
|
/* Are there pending TSD interrupts? */
|
||||||
|
|
||||||
sam_adc_putreg32(priv->dev, SAM_ADC_IDR, ADC_TSD_INTS);
|
if ((pending & ADC_TSD_ALLINTS) != 0)
|
||||||
|
|
||||||
/* Schedule sampling to occur on the worker thread */
|
|
||||||
|
|
||||||
ret = sam_schedule(priv);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
{
|
||||||
idbg("ERROR: sam_schedule failed: %d\n", ret);
|
/* Disable further touchscreen interrupts */
|
||||||
|
|
||||||
|
sam_adc_putreg32(priv->dev, 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 & ADC_TSD_ALLSTATUS;
|
||||||
|
|
||||||
|
/* Schedule sampling to occur by the interrupt bottom half on the
|
||||||
|
* worker thread.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = sam_schedule(priv, pending);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
idbg("ERROR: sam_schedule failed: %d\n", ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user