summaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src/sama5/sam_adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/arch/arm/src/sama5/sam_adc.c')
-rw-r--r--nuttx/arch/arm/src/sama5/sam_adc.c345
1 files changed, 265 insertions, 80 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_adc.c b/nuttx/arch/arm/src/sama5/sam_adc.c
index 4249a44ab..d8b58010d 100644
--- a/nuttx/arch/arm/src/sama5/sam_adc.c
+++ b/nuttx/arch/arm/src/sama5/sam_adc.c
@@ -1,7 +1,6 @@
/************************************************************************************
* arch/arm/src/sama5/sam_adc.c
*
- *
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
@@ -65,6 +64,64 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
+/* Get the set of channel interrupts to enable */
+
+#define SAMA5_CHAN0_ENABLE 0
+#define SAMA5_CHAN1_ENABLE 0
+#define SAMA5_CHAN2_ENABLE 0
+#define SAMA5_CHAN3_ENABLE 0
+#define SAMA5_CHAN4_ENABLE 0
+#define SAMA5_CHAN5_ENABLE 0
+#define SAMA5_CHAN6_ENABLE 0
+#define SAMA5_CHAN7_ENABLE 0
+#define SAMA5_CHAN8_ENABLE 0
+#define SAMA5_CHAN9_ENABLE 0
+#define SAMA5_CHAN10_ENABLE 0
+#define SAMA5_CHAN11_ENABLE 0
+
+#if defined(CONFIG_SAMA5_ADC_CHAN0)
+# undef SAMA5_CHAN0_ENABLE
+# define SAMA5_CHAN0_ENABLE ADC_INT_EOC0
+#elif defined(CONFIG_SAMA5_ADC_CHAN1)
+# undef SAMA5_CHAN1_ENABLE
+# define SAMA5_CHAN1_ENABLE ADC_INT_EOC1
+#elif defined(CONFIG_SAMA5_ADC_CHAN2)
+# undef SAMA5_CHAN2_ENABLE
+# define SAMA5_CHAN2_ENABLE ADC_INT_EOC2
+#elif defined(CONFIG_SAMA5_ADC_CHAN3)
+# undef SAMA5_CHAN3_ENABLE
+# define SAMA5_CHAN3_ENABLE ADC_INT_EOC3
+#elif defined(CONFIG_SAMA5_ADC_CHAN4)
+# undef SAMA5_CHAN4_ENABLE
+# define SAMA5_CHAN4_ENABLE ADC_INT_EOC4
+#elif defined(CONFIG_SAMA5_ADC_CHAN5)
+# undef SAMA5_CHAN5_ENABLE
+# define SAMA5_CHAN5_ENABLE ADC_INT_EOC5
+#elif defined(CONFIG_SAMA5_ADC_CHAN6)
+# undef SAMA5_CHAN6_ENABLE
+# define SAMA5_CHAN6_ENABLE ADC_INT_EOC6
+#elif defined(CONFIG_SAMA5_ADC_CHAN7)
+# undef SAMA5_CHAN7_ENABLE
+# define SAMA5_CHAN7_ENABLE ADC_INT_EOC7
+#elif defined(CONFIG_SAMA5_ADC_CHAN8)
+# undef SAMA5_CHAN8_ENABLE
+# define SAMA5_CHAN8_ENABLE ADC_INT_EOC8
+#elif defined(CONFIG_SAMA5_ADC_CHAN9)
+# undef SAMA5_CHAN9_ENABLE
+# define SAMA5_CHAN9_ENABLE ADC_INT_EOC9
+#elif defined(CONFIG_SAMA5_ADC_CHAN10)
+# undef SAMA5_CHAN10_ENABLE
+# define SAMA5_CHAN10_ENABLE ADC_INT_EOC10
+#elif defined(CONFIG_SAMA5_ADC_CHAN11)
+# undef SAMA5_CHAN11_ENABLE
+# define SAMA5_CHAN11_ENABLE ADC_INT_EOC11
+#endif
+
+#define SAMA5_CHAN_ENABLE \
+ (SAMA5_CHAN0_ENABLE || SAMA5_CHAN1_ENABLE || SAMA5_CHAN2_ENABLE || \
+ SAMA5_CHAN3_ENABLE || SAMA5_CHAN4_ENABLE || SAMA5_CHAN5_ENABLE || \
+ SAMA5_CHAN6_ENABLE || SAMA5_CHAN7_ENABLE || SAMA5_CHAN8_ENABLE || \
+ SAMA5_CHAN9_ENABLE || SAMA5_CHAN10_ENABLE || SAMA5_CHAN11_ENABLE)
/****************************************************************************
* Private Types
@@ -74,13 +131,17 @@
struct sam_adc_s
{
+#ifdef SAMA5_ADC_HAVE_CHANNELS
+ struct adc_dev_s dev; /* The external via of the ADC device */
+#endif
+
/* Debug stuff */
#ifdef CONFIG_SAMA5_ADC_REGDEBUG
- bool wrlast; /* Last was a write */
- uintptr_t addrlast; /* Last address */
- uint32_t vallast; /* Last value */
- int ntimes; /* Number of times */
+ bool wrlast; /* Last was a write */
+ uintptr_t addrlast; /* Last address */
+ uint32_t vallast; /* Last value */
+ int ntimes; /* Number of times */
#endif
};
@@ -90,31 +151,32 @@ struct sam_adc_s
/* Register operations ******************************************************/
#if defined(CONFIG_SAMA5_ADC_REGDEBUG) && defined(CONFIG_DEBUG)
-static bool sam_adc_checkreg(struct sam_gmac_s *priv, bool wr,
- uint32_t regval, uintptr_t address);
-static uint32_t sam_adc_getreg(struct sam_gmac_s *priv, uintptr_t addr);
-static void sam_adc_putreg(struct sam_gmac_s *priv, uintptr_t addr, uint32_t val);
-#else
-# define sam_adc_getreg(priv,addr) getreg32(addr)
-# define sam_adc_putreg(priv,addr,val) putreg32(val,addr)
+static bool sam_adc_checkreg(struct sam_adc_s *priv, bool wr,
+ uint32_t regval, uintptr_t address);
#endif
/* ADC interrupt handling */
+#ifdef SAMA5_ADC_HAVE_CHANNELS
+static void sam_adc_endconversion(struct sam_adc_s *priv, uint32_t pending);
+#endif
static int sam_adc_interrupt(int irq, void *context);
/* ADC methods */
-static void sam_adc_reset(FAR struct adc_dev_s *dev);
-static int sam_adc_setup(FAR struct adc_dev_s *dev);
-static void sam_adc_shutdown(FAR struct adc_dev_s *dev);
-static void sam_adc_rxint(FAR struct adc_dev_s *dev, bool enable);
-static int sam_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg);
+#ifdef SAMA5_ADC_HAVE_CHANNELS
+static void sam_adc_reset(struct adc_dev_s *dev);
+static int sam_adc_setup(struct adc_dev_s *dev);
+static void sam_adc_shutdown(struct adc_dev_s *dev);
+static void sam_adc_rxint(struct adc_dev_s *dev, bool enable);
+static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg);
+#endif
/****************************************************************************
* Private Data
****************************************************************************/
+#ifdef SAMA5_ADC_HAVE_CHANNELS
/* ADC lower half device operations */
static const struct adc_ops_s g_adcops =
@@ -125,20 +187,21 @@ static const struct adc_ops_s g_adcops =
.ao_rxint = sam_adc_rxint,
.ao_ioctl = sam_adc_ioctl,
};
+#endif
/* ADC internal state */
-static struct sam_adc_s g_adcpriv =
-{
-};
+static struct sam_adc_s g_adcpriv;
+#ifdef SAMA5_ADC_HAVE_CHANNELS
/* ADC device instance */
static struct adc_dev_s g_adcdev =
{
.ad_ops = &g_adcops,
- .ad_priv = &g_adcpriv,
+ .ad_priv = &g_adcpriv.dev,
};
+#endif
/****************************************************************************
* Private Functions
@@ -161,7 +224,7 @@ static struct adc_dev_s g_adcdev =
****************************************************************************/
#ifdef CONFIG_SAMA5_ADC_REGDEBUG
-static bool sam_adc_checkreg(struct sam_gmac_s *priv, bool wr,
+static bool sam_adc_checkreg(struct sam_adc_s *priv, bool wr,
uint32_t regval, uintptr_t address)
{
if (wr == priv->wrlast && /* Same kind of access? */
@@ -198,48 +261,7 @@ static bool sam_adc_checkreg(struct sam_gmac_s *priv, bool wr,
}
#endif
-/****************************************************************************
- * Name: sam_adc_getreg
- *
- * Description:
- * Read any 32-bit register using an absolute address.
- *
- ****************************************************************************/
-
-#ifdef CONFIG_SAMA5_ADC_REGDEBUG
-static uint32_t sam_adc_getreg(struct sam_gmac_s *priv, uintptr_t address)
-{
- uint32_t regval = getreg32(address);
-
- if (sam_adc_checkreg(priv, false, regval, address))
- {
- lldbg("%08x->%08x\n", address, regval);
- }
-
- return regval;
-}
-#endif
-
-/****************************************************************************
- * Name: sam_adc_putreg
- *
- * Description:
- * Write to any 32-bit register using an absolute address.
- *
- ****************************************************************************/
-
-#ifdef CONFIG_SAMA5_ADC_REGDEBUG
-static void sam_adc_putreg(struct sam_gmac_s *priv, uintptr_t address,
- uint32_t regval)
-{
- if (sam_adc_checkreg(priv, true, regval, address))
- {
- lldbg("%08x<-%08x\n", address, regval);
- }
-
- putreg32(regval, address);
-}
-#endif
+#ifdef SAMA5_ADC_HAVE_CHANNELS
/****************************************************************************
* Name: sam_adc_reset
@@ -250,15 +272,20 @@ static void sam_adc_putreg(struct sam_gmac_s *priv, uintptr_t address,
*
****************************************************************************/
-static void sam_adc_reset(FAR struct adc_dev_s *dev)
+static void sam_adc_reset(struct adc_dev_s *dev)
{
- FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)dev->ad_priv;
+ struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv;
irqstate_t flags;
uint32_t regval;
+ /* Reset the ADC controller */
+
flags = irqsave();
-#warning Missing logic
+ sam_adc_putreg(priv, SAM_ADC_CR, ADC_CR_SWRST);
+
+ /* Reset Mode Register */
+ sam_adc_putreg(priv, SAM_ADC_MR, 0);
irqrestore(flags);
}
@@ -273,9 +300,9 @@ static void sam_adc_reset(FAR struct adc_dev_s *dev)
*
****************************************************************************/
-static int sam_adc_setup(FAR struct adc_dev_s *dev)
+static int sam_adc_setup(struct adc_dev_s *dev)
{
- FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)dev->ad_priv;
+ struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv;
int ret;
/* Attach the ADC interrupt */
@@ -302,15 +329,15 @@ static int sam_adc_setup(FAR struct adc_dev_s *dev)
*
****************************************************************************/
-static void sam_adc_shutdown(FAR struct adc_dev_s *dev)
+static void sam_adc_shutdown(struct adc_dev_s *dev)
{
- FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)dev->ad_priv;
+ struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv;
/* Disable ADC interrupts, both at the level of the ADC device and at the
* level of the NVIC.
*/
-#warning Missing logic
+ sam_adc_putreg32(priv, SAM_ADC_IDR, ADC_TSD_INTS);
up_disable_irq(SAM_IRQ_ADC);
/* Then detach the ADC interrupt handler. */
@@ -326,18 +353,23 @@ static void sam_adc_shutdown(FAR struct adc_dev_s *dev)
*
****************************************************************************/
-static void sam_adc_rxint(FAR struct adc_dev_s *dev, bool enable)
+static void sam_adc_rxint(struct adc_dev_s *dev, bool enable)
{
- FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)dev->ad_priv;
+ struct sam_adc_s *priv = (struct sam_adc_s *)dev->ad_priv;
/* Are we enabling or disabling? */
+
if (enable)
{
-#warning Missing logic
+ /* Enable channel interrupts */
+
+ sam_adc_putreg32(priv, SAM_ADC_IER, SAMA5_CHAN_ENABLE);
}
else
{
-#warning Missing logic
+ /* Disable channel interrupts */
+
+ sam_adc_putreg32(priv, SAM_ADC_IDR, ADC_INT_EOCALL);
}
}
@@ -349,7 +381,7 @@ static void sam_adc_rxint(FAR struct adc_dev_s *dev, bool enable)
*
****************************************************************************/
-static int sam_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
+static int sam_adc_ioctl(struct adc_dev_s *dev, int cmd, unsigned long arg)
{
/* No ioctl commands supported */
@@ -357,6 +389,37 @@ static int sam_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
}
/****************************************************************************
+ * 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:
@@ -366,11 +429,46 @@ static int sam_adc_ioctl(FAR struct adc_dev_s *dev, int cmd, unsigned long arg)
static int sam_adc_interrupt(int irq, void *context)
{
- FAR struct sam_adc_s *priv = (FAR struct sam_adc_s *)g_adcdev.ad_priv;
+ 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;
-#warning Missing logic
+ /* 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;
}
@@ -389,12 +487,54 @@ static int sam_adc_interrupt(int irq, void *context)
*
****************************************************************************/
-FAR struct adc_dev_s *sam_adc_initialize(void)
+struct adc_dev_s *sam_adc_initialize(void)
{
/* Enable the ADC peripheral clock*/
sam_adc_enableclk();
+ /* Configure ADC pins */
+
+#ifdef CONFIG_SAMA5_ADC_CHAN0
+ sam_configpio(PIO_ADC_AD0);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN1
+ sam_configpio(PIO_ADC_AD1);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN2
+ sam_configpio(PIO_ADC_AD2);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN3
+ sam_configpio(PIO_ADC_AD3);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN4
+ sam_configpio(PIO_ADC_AD4);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN5
+ sam_configpio(PIO_ADC_AD5);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN6
+ sam_configpio(PIO_ADC_AD6);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN7
+ sam_configpio(PIO_ADC_AD7);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN8
+ sam_configpio(PIO_ADC_AD8);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN9
+ sam_configpio(PIO_ADC_AD9);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN10
+ sam_configpio(PIO_ADC_AD10);
+#endif
+#ifdef CONFIG_SAMA5_ADC_CHAN11
+ sam_configpio(PIO_ADC_AD11);
+#endif
+#if 0
+ sam_configpio(PIO_ADC_TRG);
+#endif
+
/* Reset the ADC controller */
sam_adc_putreg(priv, SAM_ADC_CR, ADC_CR_SWRST);
@@ -408,4 +548,49 @@ FAR struct adc_dev_s *sam_adc_initialize(void)
return &g_adcdev;
}
+/****************************************************************************
+ * Name: sam_adc_getreg
+ *
+ * Description:
+ * Read any 32-bit register using an absolute address.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_ADC_REGDEBUG
+static uint32_t sam_adc_getreg(ADC_HANDLE handle, uintptr_t address)
+{
+ struct sam_adc_s *priv = (struct sam_adc_s *)handle;
+ uint32_t regval = getreg32(address);
+
+ if (sam_adc_checkreg(priv, false, regval, address))
+ {
+ lldbg("%08x->%08x\n", address, regval);
+ }
+
+ return regval;
+}
+#endif
+
+/****************************************************************************
+ * Name: sam_adc_putreg
+ *
+ * Description:
+ * Write to any 32-bit register using an absolute address.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SAMA5_ADC_REGDEBUG
+void sam_adc_putreg(ADC_HANDLE handle, uintptr_t address, uint32_t regval)
+{
+ struct sam_adc_s *priv = (struct sam_adc_s *)handle;
+
+ if (sam_adc_checkreg(priv, true, regval, address))
+ {
+ lldbg("%08x<-%08x\n", address, regval);
+ }
+
+ putreg32(regval, address);
+}
+#endif
+
#endif /* CONFIG_SAMA5_ADC */