mirror of
https://github.com/apache/nuttx.git
synced 2026-05-23 14:58: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).
|
||||
* configs/freedom-kl25z/minnsh: A new configuration that is
|
||||
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
|
||||
now functional. From Max Holtzberg (2013-9-30).
|
||||
* tools/define.sh: 'cut' long because as it once did. Script
|
||||
|
||||
+205
-84
@@ -57,6 +57,7 @@
|
||||
|
||||
#include "chip.h"
|
||||
#include "chip/sam_adc.h"
|
||||
#include "sam_dmac.h"
|
||||
#include "sam_adc.h"
|
||||
|
||||
#if defined(CONFIG_SAMA5_ADC)
|
||||
@@ -123,6 +124,19 @@
|
||||
SAMA5_CHAN6_ENABLE || SAMA5_CHAN7_ENABLE || SAMA5_CHAN8_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
|
||||
****************************************************************************/
|
||||
@@ -133,6 +147,10 @@ struct sam_adc_s
|
||||
{
|
||||
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
||||
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
|
||||
|
||||
/* Debug stuff */
|
||||
@@ -155,6 +173,14 @@ static bool sam_adc_checkreg(struct sam_adc_s *priv, bool wr,
|
||||
uint32_t regval, uintptr_t address);
|
||||
#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 */
|
||||
|
||||
#ifdef SAMA5_ADC_HAVE_CHANNELS
|
||||
@@ -207,6 +233,9 @@ static struct adc_dev_s g_adcdev =
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Register Operations
|
||||
****************************************************************************/
|
||||
/****************************************************************************
|
||||
* 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
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
@@ -278,6 +470,12 @@ static void sam_adc_reset(struct adc_dev_s *dev)
|
||||
irqstate_t flags;
|
||||
uint32_t regval;
|
||||
|
||||
#ifdef CONFIG_SAMA5_ADC_DMA
|
||||
/* Stop any ongoing DMA */
|
||||
|
||||
sam_dmastop(priv->dma);
|
||||
#endif
|
||||
|
||||
/* Reset the ADC controller */
|
||||
|
||||
flags = irqsave();
|
||||
@@ -388,90 +586,6 @@ static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg)
|
||||
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
|
||||
****************************************************************************/
|
||||
@@ -535,6 +649,13 @@ struct adc_dev_s *sam_adc_initialize(void)
|
||||
sam_configpio(PIO_ADC_TRG);
|
||||
#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 */
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#define DEV_FORMAT "/dev/input%d"
|
||||
#define DEV_NAMELEN 16
|
||||
#define DEV_FORMAT "/dev/input%d"
|
||||
#define DEV_NAMELEN 16
|
||||
|
||||
/* 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
|
||||
* first pendown (but can't overflow).
|
||||
@@ -80,13 +80,36 @@
|
||||
|
||||
#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
|
||||
****************************************************************************/
|
||||
|
||||
/* This describes the state of one contact */
|
||||
|
||||
enum sam_contact_3
|
||||
enum sam_contact_e
|
||||
{
|
||||
CONTACT_NONE = 0, /* No contact */
|
||||
CONTACT_DOWN, /* First contact */
|
||||
@@ -107,13 +130,15 @@ struct sam_sample_s
|
||||
|
||||
/* 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 id; /* Current touch point ID */
|
||||
uint8_t status; /* Data ready/pen status bit set */
|
||||
volatile bool penchange; /* An unreported event is buffered */
|
||||
uint16_t threshx; /* Thresholding X 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 waitsem; /* Used to wait for the availability of data */
|
||||
|
||||
@@ -138,22 +163,22 @@ struct sam_dev_s
|
||||
|
||||
/* Interrupt bottom half logic and data sampling */
|
||||
|
||||
static void sam_notify(FAR struct sam_dev_s *priv);
|
||||
static int sam_sample(FAR struct sam_dev_s *priv,
|
||||
FAR struct sam_sample_s *sample);
|
||||
static int sam_waitsample(FAR struct sam_dev_s *priv,
|
||||
FAR struct sam_sample_s *sample);
|
||||
static void sam_bottomhalf(FAR void *arg);
|
||||
static void sam_notify(struct sam_tsd_s *priv);
|
||||
static int sam_sample(struct sam_tsd_s *priv, struct sam_sample_s *sample);
|
||||
static int sam_waitsample(struct sam_tsd_s *priv,
|
||||
struct sam_sample_s *sample);
|
||||
static void sam_bottomhalf(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 */
|
||||
|
||||
static int sam_open(FAR struct file *filep);
|
||||
static int sam_close(FAR struct file *filep);
|
||||
static ssize_t sam_read(FAR struct file *filep, FAR char *buffer,
|
||||
size_t len);
|
||||
static int sam_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
|
||||
static int sam_open(struct file *filep);
|
||||
static int sam_close(struct file *filep);
|
||||
static ssize_t sam_read(struct file *filep, char *buffer, size_t len);
|
||||
static int sam_ioctl(struct file *filep, int cmd, unsigned long arg);
|
||||
#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
|
||||
|
||||
/****************************************************************************
|
||||
@@ -177,7 +202,7 @@ static const struct file_operations g_tsdops =
|
||||
|
||||
/* The driver state structure is pre-allocated. */
|
||||
|
||||
static struct sam_dev_s g_tsd;
|
||||
static struct sam_tsd_s g_tsd;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
@@ -187,7 +212,7 @@ static struct sam_dev_s g_tsd;
|
||||
* 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
|
||||
int i;
|
||||
@@ -230,8 +255,7 @@ static void sam_notify(FAR struct sam_dev_s *priv)
|
||||
* Name: sam_sample
|
||||
****************************************************************************/
|
||||
|
||||
static int sam_sample(FAR struct sam_dev_s *priv,
|
||||
FAR struct sam_sample_s *sample)
|
||||
static int sam_sample(struct sam_tsd_s *priv, struct sam_sample_s *sample)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int ret = -EAGAIN;
|
||||
@@ -284,8 +308,7 @@ static int sam_sample(FAR struct sam_dev_s *priv,
|
||||
* Name: sam_waitsample
|
||||
****************************************************************************/
|
||||
|
||||
static int sam_waitsample(FAR struct sam_dev_s *priv,
|
||||
FAR struct sam_sample_s *sample)
|
||||
static int sam_waitsample(struct sam_tsd_s *priv, struct sam_sample_s *sample)
|
||||
{
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
@@ -361,58 +384,29 @@ errout:
|
||||
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
|
||||
*
|
||||
* 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 y;
|
||||
uint16_t xdiff;
|
||||
@@ -428,6 +422,10 @@ static void sam_bottomhalf(FAR void *arg)
|
||||
|
||||
wd_cancel(priv->wdog);
|
||||
|
||||
/* Get the set of unmasked, pending ADC interrupts */
|
||||
|
||||
pending = priv->pending;
|
||||
|
||||
/* Get exclusive access to the driver data structure */
|
||||
|
||||
do
|
||||
@@ -556,18 +554,81 @@ static void sam_bottomhalf(FAR void *arg)
|
||||
ignored:
|
||||
/* 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 */
|
||||
|
||||
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
|
||||
****************************************************************************/
|
||||
|
||||
static int sam_open(FAR struct file *filep)
|
||||
static int sam_open(struct file *filep)
|
||||
{
|
||||
ivdbg("Opening\n");
|
||||
return OK;
|
||||
@@ -577,7 +638,7 @@ static int sam_open(FAR struct file *filep)
|
||||
* Name: sam_close
|
||||
****************************************************************************/
|
||||
|
||||
static int sam_close(FAR struct file *filep)
|
||||
static int sam_close(struct file *filep)
|
||||
{
|
||||
ivdbg("Closing\n");
|
||||
return OK;
|
||||
@@ -587,11 +648,11 @@ static int sam_close(FAR struct file *filep)
|
||||
* 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;
|
||||
FAR struct sam_dev_s *priv;
|
||||
FAR struct touch_sample_s *report;
|
||||
struct inode *inode;
|
||||
struct sam_tsd_s *priv;
|
||||
struct touch_sample_s *report;
|
||||
struct sam_sample_s sample;
|
||||
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;
|
||||
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
|
||||
report = (FAR struct touch_sample_s *)buffer;
|
||||
report = (struct touch_sample_s *)buffer;
|
||||
memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1));
|
||||
report->npoints = 1;
|
||||
report->point[0].id = sample.id;
|
||||
report->point[0].x = sample.x;
|
||||
report->point[0].y = sample.y;
|
||||
report->npoints = 1;
|
||||
report->point[0].id = sample.id;
|
||||
report->point[0].x = sample.x;
|
||||
report->point[0].y = sample.y;
|
||||
|
||||
/* Report the appropriate flags */
|
||||
|
||||
@@ -716,18 +777,18 @@ errout:
|
||||
* 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;
|
||||
FAR struct sam_dev_s *priv;
|
||||
int ret;
|
||||
struct inode *inode;
|
||||
struct sam_tsd_s *priv;
|
||||
int ret;
|
||||
|
||||
ivdbg("cmd: %d arg: %ld\n", cmd, arg);
|
||||
DEBUGASSERT(filep);
|
||||
inode = filep->f_inode;
|
||||
|
||||
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 */
|
||||
|
||||
@@ -758,20 +819,19 @@ static int sam_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef CONFIG_DISABLE_POLL
|
||||
static int sam_poll(FAR struct file *filep, FAR struct pollfd *fds,
|
||||
bool setup)
|
||||
static int sam_poll(struct file *filep, struct pollfd *fds, bool setup)
|
||||
{
|
||||
FAR struct inode *inode;
|
||||
FAR struct sam_dev_s *priv;
|
||||
int ret = OK;
|
||||
int i;
|
||||
struct inode *inode;
|
||||
struct sam_tsd_s *priv;
|
||||
int ret = OK;
|
||||
int i;
|
||||
|
||||
ivdbg("setup: %d\n", (int)setup);
|
||||
DEBUGASSERT(filep && fds);
|
||||
inode = filep->f_inode;
|
||||
|
||||
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? */
|
||||
|
||||
@@ -871,7 +931,7 @@ errout:
|
||||
|
||||
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];
|
||||
int ret;
|
||||
|
||||
@@ -883,7 +943,7 @@ int sam_tsd_register(struct adc_dev_s *dev, int minor)
|
||||
|
||||
/* 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->wdog = wd_create(); /* Create a watchdog timer */
|
||||
priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */
|
||||
@@ -941,29 +1001,43 @@ errout_with_priv:
|
||||
* Handles ADC interrupts associated with touchscreen channels
|
||||
*
|
||||
* Input parmeters:
|
||||
* None
|
||||
* pending - Current set of pending interrupts being handled
|
||||
*
|
||||
* Returned Value:
|
||||
* 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;
|
||||
|
||||
/* Disable further touchscreen interrupts */
|
||||
/* Are there pending TSD interrupts? */
|
||||
|
||||
sam_adc_putreg32(priv->dev, SAM_ADC_IDR, ADC_TSD_INTS);
|
||||
|
||||
/* Schedule sampling to occur on the worker thread */
|
||||
|
||||
ret = sam_schedule(priv);
|
||||
if (ret < 0)
|
||||
if ((pending & ADC_TSD_ALLINTS) != 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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user