]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/adc.c
Add SAMA5D2 Xplained IAR demo.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D2x_Xplained_IAR / AtmelFiles / drivers / peripherals / adc.c
diff --git a/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/adc.c b/FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/adc.c
new file mode 100644 (file)
index 0000000..9aa239f
--- /dev/null
@@ -0,0 +1,639 @@
+/* ----------------------------------------------------------------------------\r
+ *         SAM Software Package License\r
+ * ----------------------------------------------------------------------------\r
+ * Copyright (c) 2015, Atmel Corporation\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright notice,\r
+ * this list of conditions and the disclaimer below.\r
+ *\r
+ * Atmel's name may not be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ *\r
+ * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ * ----------------------------------------------------------------------------\r
+ */\r
+\r
+/** \addtogroup adc_module Working with ADC\r
+ * \ingroup peripherals_module\r
+ * \section Purpose\r
+ * The ADC driver provides the interface to configure and use the ADC peripheral.\r
+ * \n\r
+ *\r
+ * It converts the analog input to digital format. The converted result could be\r
+ * 12bit.\r
+ *\r
+ * To Enable a ADC conversion,the user has to follow these few steps:\r
+ * <ul>\r
+ * <li> Select an appropriate reference voltage on ADVREF   </li>\r
+ * <li> Configure the ADC according to its requirements and special needs,which\r
+ * could be  broken down into several parts:\r
+ * -#   Select the resolution by setting or clearing ADC_MR_LOWRES bit in\r
+ *      ADC_MR (Mode Register)\r
+ * -#   Set ADC clock by setting ADC_MR_PRESCAL bits in ADC_MR, the clock is\r
+ *      calculated with ADCClock = MCK / ( (PRESCAL+1) * 2 )\r
+ * -#   Set Startup Time,Tracking Clock cycles and Transfer Clock respectively\r
+ *      in ADC_MR.\r
+ </li>\r
+ * <li> Start conversion by setting ADC_CR_START in ADC_CR. </li>\r
+ * </ul>\r
+ *\r
+ * \section Usage\r
+ * <ul>\r
+ * <li> Initialize the ADC controller using adc_initialize().\r
+ * <li> ADC clock and timing configuration using adc_set_clock() and adc_set_timing().\r
+ * <li> For ADC trigger using adc_set_trigger(), adc_set_trigger_mode() and\r
+ * adc_set_trigger_period().\r
+ * <li> For ADC sequence mode using adc_set_sequence_mode(), adc_set_sequence() and\r
+ * adc_set_sequence_by_list().\r
+ * <li> For ADC compare mode using adc_set_compare_channel(), adc_set_compare_mode()\r
+ * and adc_set_comparison_window().\r
+ * <li> ADC works with touchscreen using adc_ts_calibration(), adc_set_ts_mode(),\r
+ * adc_set_ts_debounce(), adc_set_ts_pen_detect(), adc_set_ts_average(),\r
+ * adc_get_ts_xposition(), adc_get_ts_yposition() and adc_get_ts_pressure().\r
+ * </li>\r
+ * </ul>\r
+ *\r
+ * For more accurate information, please look at the ADC section of the\r
+ * Datasheet.\r
+ *\r
+ * Related files :\n\r
+ * \ref adc.c\n\r
+ * \ref adc.h\n\r
+ */\r
+/**\r
+ * \file\r
+ *\r
+ * Implementation of Analog-to-Digital Converter (ADC).\r
+ *\r
+ */\r
+/*----------------------------------------------------------------------------\r
+ *        Headers\r
+ *----------------------------------------------------------------------------*/\r
+\r
+#include "chip.h"\r
+#include "peripherals/adc.h"\r
+#include "peripherals/pmc.h"\r
+\r
+#include "trace.h"\r
+\r
+#include <stdio.h>\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Local definitions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+#ifndef ADC_MR_TRANSFER\r
+/* for compatibility with older peripheral versions */\r
+#define ADC_MR_TRANSFER(x) 0\r
+#endif\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Local variables\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/** Current working clock */\r
+static uint32_t _adc_clock = 0;\r
+\r
+/*----------------------------------------------------------------------------\r
+ *        Exported functions\r
+ *----------------------------------------------------------------------------*/\r
+\r
+uint32_t adc_num_channels(void)\r
+{\r
+       return ARRAY_SIZE(ADC->ADC_CDR);\r
+}\r
+\r
+/**\r
+ * \brief Initialize the ADC controller\r
+ *\r
+ */\r
+void adc_initialize(void)\r
+{\r
+       /* Enable peripheral clock */\r
+       pmc_enable_peripheral(ID_ADC);\r
+\r
+       /*  Reset the controller */\r
+       ADC->ADC_CR = ADC_CR_SWRST;\r
+\r
+       /* Reset Mode Register */\r
+       ADC->ADC_MR = 0;\r
+\r
+}\r
+\r
+/**\r
+ * \brief Set ADC clock.\r
+ *\r
+ * \param clk adc clock frequency\r
+ *\r
+ * \return ADC clock\r
+ */\r
+uint32_t adc_set_clock(uint32_t clk)\r
+{\r
+       uint32_t prescale, mode_reg;\r
+       uint32_t mck = pmc_get_peripheral_clock(ID_ADC);\r
+       /* Formula for PRESCAL is:\r
+          ADCClock = MCK / ( (PRESCAL+1) * 2 )\r
+          PRESCAL = (MCK / (2 * ADCCLK)) + 1\r
+          First, we do the division, multiplied by 10 to get higher precision\r
+          If the last digit is not zero, we round up to avoid generating a higher\r
+          than required frequency. */\r
+       prescale = (mck * 5) / clk;\r
+       if (prescale % 10)\r
+               prescale = prescale / 10;\r
+       else {\r
+               if (prescale == 0)\r
+                       return 0;\r
+               prescale = prescale / 10 - 1;\r
+       }\r
+\r
+       mode_reg = ADC_MR_PRESCAL(prescale);\r
+       if (mode_reg == 0)\r
+               return 0;\r
+\r
+       mode_reg |= (ADC->ADC_MR & ~ADC_MR_PRESCAL_Msk);\r
+       ADC->ADC_MR = mode_reg;\r
+\r
+       _adc_clock = mck / (prescale + 1) / 2;\r
+       //_adc_clock = _adc_clock / 1000 * 1000;\r
+       return _adc_clock;\r
+}\r
+\r
+void adc_enable_it(uint32_t mask)\r
+{\r
+       ADC->ADC_IER |= mask;\r
+}\r
+\r
+void adc_disable_it(uint32_t mask)\r
+{\r
+       ADC->ADC_IER &= ~mask;\r
+}\r
+\r
+/**\r
+ * \brief Set ADC timing.\r
+ *\r
+ * \param startup startup value\r
+ * \param tracking tracking value\r
+ * \param settling settling value\r
+ */\r
+void adc_set_timing(uint32_t startup, uint32_t tracking, uint32_t settling)\r
+{\r
+       uint32_t mode_reg;\r
+\r
+#ifndef CONFIG_HAVE_ADC_SETTLING_TIME\r
+       if (settling) {\r
+               settling = 0;\r
+               trace_warning("adc: Analog settling time not supported, IGNORED!\r\n");\r
+       }\r
+#endif\r
+\r
+       mode_reg = ADC->ADC_MR;\r
+       mode_reg &= (~ADC_MR_STARTUP_Msk) & (~ADC_MR_TRACKTIM_Msk);\r
+\r
+       /* Formula:\r
+        *     Startup  Time = startup value / ADCClock\r
+        *     Transfer Time = (TRANSFER * 2 + 3) / ADCClock\r
+        *     Tracking Time = (TRACKTIM + 1) / ADCClock\r
+        *     Settling Time = settling value / ADCClock\r
+        */\r
+       mode_reg |= ADC_MR_STARTUP(startup);\r
+       mode_reg |= ADC_MR_TRACKTIM(tracking);\r
+       mode_reg |= ADC_MR_TRANSFER(2);\r
+#ifdef CONFIG_HAVE_ADC_SETTLING_TIME\r
+       mode_reg |=  ADC_MR_SETTLING(settling);\r
+#endif\r
+       ADC->ADC_MR |= mode_reg;\r
+}\r
+\r
+void adc_set_trigger_mode(uint32_t mode)\r
+{\r
+       uint32_t trg_reg = ADC->ADC_TRGR & ~ADC_TRGR_TRGMOD_Msk;\r
+       ADC->ADC_TRGR = trg_reg | mode;\r
+}\r
+\r
+void adc_set_sleep_mode(uint8_t enable)\r
+{\r
+       if (enable) {\r
+               ADC->ADC_MR |= ADC_MR_SLEEP;\r
+       } else {\r
+               ADC->ADC_MR &= ~ADC_MR_SLEEP;\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Enable/Disable seqnence mode.\r
+ *\r
+ * \param enable Enable/Disable seqnence mode.\r
+ */\r
+void adc_set_sequence_mode(uint8_t enable)\r
+{\r
+       if (enable) {\r
+               /* User Sequence Mode: The sequence respects what is defined in\r
+                  ADC_SEQR1 and ADC_SEQR2 */\r
+               ADC->ADC_MR |= ADC_MR_USEQ;\r
+       } else {\r
+               /* Normal Mode: The controller converts channels in a simple numeric order. */\r
+               ADC->ADC_MR &= ~ADC_MR_USEQ;\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Set channel sequence.\r
+ *\r
+ * \param seq1 Sequence 1 ~ 8  channel number.\r
+ * \param seq2 Sequence 9 ~ 16 channel number.\r
+ */\r
+\r
+void adc_set_sequence(uint32_t seq1, uint32_t seq2)\r
+{\r
+       ADC->ADC_SEQR1 = seq1;\r
+#ifdef CONFIG_HAVE_ADC_SEQ_REG2\r
+       ADC->ADC_SEQR2 = seq2;\r
+#endif\r
+}\r
+\r
+/**\r
+ * \brief Set channel sequence by given channel list.\r
+ *\r
+ * \param channel_list Channel list.\r
+ * \param len  Number of channels in list.\r
+ */\r
+\r
+void adc_set_sequence_by_list(uint8_t channel_list[], uint8_t len)\r
+{\r
+       uint8_t i;\r
+       uint8_t shift;\r
+\r
+       if (len <= 8) {\r
+               ADC->ADC_SEQR1 = 0;\r
+               for (i = 0, shift = 0; i < len; i++, shift += 4) {\r
+                       if (i >= len) return;\r
+                       ADC->ADC_SEQR1 |= channel_list[i] << shift;\r
+               }\r
+       }\r
+       else {\r
+               ADC->ADC_SEQR1 = 0;\r
+               for (i = 0, shift = 0; i < 8; i++, shift += 4) {\r
+                       if (i >= len) return;\r
+                       ADC->ADC_SEQR1 |= channel_list[i] << shift;\r
+               }\r
+#ifdef CONFIG_HAVE_ADC_SEQ_REG2\r
+               ADC->ADC_SEQR2 = 0;\r
+               for (i = 0, shift = 0; i < (len-8); i++, shift += 4) {\r
+                       if (i >= len) return;\r
+                       ADC->ADC_SEQR2 |= channel_list[8+i] << shift;\r
+               }\r
+#endif\r
+       }\r
+}\r
+\r
+void adc_set_tag_enable(uint8_t enable)\r
+{\r
+       if (enable) {\r
+               ADC->ADC_EMR |= ADC_EMR_TAG;\r
+       } else {\r
+               ADC->ADC_EMR &= ~ADC_EMR_TAG;\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Set compare channel.\r
+ *\r
+ * \param channel channel number to be set, xx for all channels\r
+ */\r
+void adc_set_compare_channel(uint32_t channel)\r
+{\r
+       assert(channel <= adc_num_channels());\r
+\r
+       if (channel < adc_num_channels()) {\r
+               ADC->ADC_EMR &= ~(ADC_EMR_CMPALL);\r
+               ADC->ADC_EMR &= ~(ADC_EMR_CMPSEL_Msk);\r
+               ADC->ADC_EMR |= (channel << ADC_EMR_CMPSEL_Pos);\r
+       } else {\r
+               ADC->ADC_EMR |= ADC_EMR_CMPALL;\r
+       }\r
+}\r
+\r
+/**\r
+ * \brief Set compare mode.\r
+ *\r
+ * \param mode compare mode\r
+ */\r
+void adc_set_compare_mode(uint32_t mode)\r
+{\r
+       ADC->ADC_EMR &= ~(ADC_EMR_CMPMODE_Msk);\r
+       ADC->ADC_EMR |= (mode & ADC_EMR_CMPMODE_Msk);\r
+}\r
+\r
+void adc_set_comparison_window(uint32_t window)\r
+{\r
+       ADC->ADC_CWR = window;\r
+}\r
+\r
+uint8_t adc_check_configuration(void)\r
+{\r
+       uint32_t mode_reg;\r
+       uint32_t prescale;\r
+       uint32_t clock;\r
+       uint32_t mck = pmc_get_peripheral_clock(ID_ADC);\r
+\r
+       mode_reg = ADC->ADC_MR;\r
+\r
+       prescale = (mode_reg & ADC_MR_PRESCAL_Msk) >> ADC_MR_PRESCAL_Pos;\r
+       /* Formula: ADCClock = MCK / ( (PRESCAL+1) * 2 ) */\r
+       clock = mck / ((prescale + 1) * 2);\r
+       if (clock > ADC_CLOCK_MAX) {\r
+               printf ("ADC clock is too high (out of specification: %d Hz)\r\n",\r
+                    (int) ADC_CLOCK_MAX);\r
+               return 1;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+uint32_t adc_get_converted_data(uint32_t channel)\r
+{\r
+       assert(channel < adc_num_channels());\r
+\r
+       if (channel < adc_num_channels()) {\r
+               return ADC->ADC_CDR[channel];\r
+       } else {\r
+               return 0;\r
+       }\r
+}\r
+\r
+void adc_set_startup_time(uint32_t startup)\r
+{\r
+       uint32_t start;\r
+       uint32_t mode_reg;\r
+\r
+       if (_adc_clock == 0)\r
+               return;\r
+       /* Formula for STARTUP is:\r
+          STARTUP = (time x ADCCLK) / (1000000) - 1\r
+          Division multiplied by 10 for higher precision */\r
+\r
+       start = (startup * _adc_clock) / (100000);\r
+       if (start % 10)\r
+               start /= 10;\r
+       else {\r
+               start /= 10;\r
+               if (start)\r
+                       start--;\r
+       }\r
+       if (start > 896)\r
+               mode_reg = ADC_MR_STARTUP_SUT960;\r
+       else if (start > 832)\r
+               mode_reg = ADC_MR_STARTUP_SUT896;\r
+       else if (start > 768)\r
+               mode_reg = ADC_MR_STARTUP_SUT832;\r
+       else if (start > 704)\r
+               mode_reg = ADC_MR_STARTUP_SUT768;\r
+       else if (start > 640)\r
+               mode_reg = ADC_MR_STARTUP_SUT704;\r
+       else if (start > 576)\r
+               mode_reg = ADC_MR_STARTUP_SUT640;\r
+       else if (start > 512)\r
+               mode_reg = ADC_MR_STARTUP_SUT576;\r
+       else if (start > 112)\r
+               mode_reg = ADC_MR_STARTUP_SUT512;\r
+       else if (start > 96)\r
+               mode_reg = ADC_MR_STARTUP_SUT112;\r
+       else if (start > 80)\r
+               mode_reg = ADC_MR_STARTUP_SUT96;\r
+       else if (start > 64)\r
+               mode_reg = ADC_MR_STARTUP_SUT80;\r
+       else if (start > 24)\r
+               mode_reg = ADC_MR_STARTUP_SUT64;\r
+       else if (start > 16)\r
+               mode_reg = ADC_MR_STARTUP_SUT24;\r
+       else if (start > 8)\r
+               mode_reg = ADC_MR_STARTUP_SUT16;\r
+       else if (start > 0)\r
+               mode_reg = ADC_MR_STARTUP_SUT8;\r
+       else\r
+               mode_reg = ADC_MR_STARTUP_SUT0;\r
+\r
+       mode_reg |= ADC->ADC_MR & ~ADC_MR_STARTUP_Msk;\r
+       ADC->ADC_MR = mode_reg;\r
+}\r
+\r
+#ifdef CONFIG_HAVE_ADC_INPUT_OFFSET\r
+/**\r
+ * \brief Enable differential input for the specified channel.\r
+ *\r
+ * \param channel ADC channel number.\r
+ */\r
+void adc_enable_channel_differential_input (uint32_t channel)\r
+{\r
+       /* (ADC_COR) Differential Inputs for Channel n */\r
+       ADC->ADC_COR |= 0x01u << (16 + channel);\r
+}\r
+\r
+/**\r
+ * \brief Disable differential input for the specified channel.\r
+ *\r
+ * \param channel ADC channel number.\r
+ */\r
+void adc_disable_channel_differential_input(uint32_t channel)\r
+{\r
+       uint32_t temp;\r
+       temp = ADC->ADC_COR;\r
+       ADC->ADC_COR &= 0xFFFEFFFFu << channel;\r
+       ADC->ADC_COR |= temp;\r
+}\r
+\r
+/**\r
+ * \brief Enable analog signal offset for the specified channel.\r
+ *\r
+ * \param channel ADC channel number.\r
+ */\r
+void adc_enable_channel_input_offset (uint32_t channel)\r
+{\r
+       ADC->ADC_COR |= 0x01u << channel;\r
+}\r
+\r
+/**\r
+ * \brief Disable analog signal offset for the specified channel.\r
+ *\r
+ * \param channel ADC channel number.\r
+ */\r
+void adc_disable_channel_input_offset (uint32_t channel)\r
+{\r
+       uint32_t temp;\r
+       temp = ADC->ADC_COR;\r
+       ADC->ADC_COR &= (0xFFFFFFFEu << channel);\r
+       ADC->ADC_COR |= temp;\r
+}\r
+#endif /* CONFIG_HAVE_ADC_INPUT_OFFSET */\r
+\r
+#ifdef CONFIG_HAVE_ADC_INPUT_GAIN\r
+/**\r
+ * \brief Configure input gain for the specified channel.\r
+ *\r
+ * \param channel ADC channel number.\r
+ * \param gain Gain value for the input.\r
+ */\r
+void adc_set_channel_input_gain (uint32_t channel, uint32_t gain)\r
+{\r
+       assert(gain < 3);\r
+       uint32_t temp;\r
+       temp = ADC->ADC_CGR;\r
+       temp |= gain << (2 * channel);\r
+       ADC->ADC_CGR = temp;\r
+}\r
+#endif /* CONFIG_HAVE_ADC_INPUT_GAIN */\r
+\r
+void adc_set_tracking_time(uint32_t dwNs)\r
+{\r
+       uint32_t dwShtim;\r
+       uint32_t mode_reg;\r
+\r
+       if (_adc_clock == 0)\r
+               return;\r
+       /* Formula for SHTIM is:\r
+          SHTIM = (time x ADCCLK) / (1000000000) - 1\r
+          Since 1 billion is close to the maximum value for an integer, we first\r
+          divide ADCCLK by 1000 to avoid an overflow */\r
+       dwShtim = (dwNs * (_adc_clock / 1000)) / 100000;\r
+       if (dwShtim % 10)\r
+               dwShtim /= 10;\r
+       else {\r
+               dwShtim /= 10;\r
+               if (dwShtim)\r
+                       dwShtim--;\r
+       }\r
+       mode_reg = ADC_MR_TRACKTIM(dwShtim);\r
+       mode_reg |= ADC->ADC_MR & ~ADC_MR_TRACKTIM_Msk;\r
+       ADC->ADC_MR = mode_reg;\r
+}\r
+\r
+void adc_set_trigger_period(uint32_t period)\r
+{\r
+       uint32_t trg_period;\r
+       uint32_t trg_reg;\r
+       if (_adc_clock == 0)\r
+               return;\r
+       trg_period = period * (_adc_clock/1000) - 1;\r
+       trg_reg = ADC->ADC_TRGR & ~ADC_TRGR_TRGPER_Msk;\r
+       trg_reg |= ADC_TRGR_TRGPER(trg_period);\r
+       ADC->ADC_TRGR = trg_reg;\r
+}\r
+\r
+void adc_ts_calibration(void)\r
+{\r
+       ADC->ADC_CR = ADC_CR_TSCALIB;\r
+}\r
+\r
+void adc_set_ts_mode(uint32_t mode)\r
+{\r
+       ADC->ADC_TSMR = (ADC->ADC_TSMR & ~ADC_TSMR_TSMODE_Msk) | mode;\r
+}\r
+\r
+void adc_configure_ext_mode(uint32_t mode)\r
+{\r
+       ADC->ADC_EMR = mode;\r
+}\r
+\r
+void adc_set_ts_debounce(uint32_t time)\r
+{\r
+       uint32_t div = 1000000000;\r
+       uint32_t clk = _adc_clock;\r
+       uint32_t dwPenbc = 0;\r
+       uint32_t target, current;\r
+       uint32_t tsmr;\r
+       if (time == 0 || _adc_clock == 0)\r
+               return;\r
+       /* Divide time & ADCCLK to avoid overflows */\r
+       while ((div > 1) && ((time % 10) == 0)) {\r
+               time /= 10;\r
+               div /= 10;\r
+       }\r
+       while ((div > 1) && ((clk & 10) == 0)) {\r
+               clk /= 10;\r
+               div /= 10;\r
+       }\r
+       /* Compute PENDBC */\r
+       target = time * clk / div;\r
+       current = 1;\r
+       while (current < target) {\r
+               dwPenbc++;\r
+               current *= 2;\r
+       }\r
+       tsmr = ADC_TSMR_PENDBC(dwPenbc);\r
+       if (tsmr == 0)\r
+               return;\r
+       tsmr |= ADC->ADC_TSMR & ~ADC_TSMR_PENDBC_Msk;\r
+       ADC->ADC_TSMR = tsmr;\r
+}\r
+\r
+void adc_set_ts_pen_detect(uint8_t enable)\r
+{\r
+       if (enable)\r
+               ADC->ADC_TSMR |= ADC_TSMR_PENDET;\r
+       else\r
+               ADC->ADC_TSMR &= ~ADC_TSMR_PENDET;\r
+}\r
+\r
+void adc_set_ts_average(uint32_t avg_2_conv)\r
+{\r
+       uint32_t mode_reg = ADC->ADC_TSMR & ~ADC_TSMR_TSAV_Msk;\r
+       uint32_t ts_av = avg_2_conv >> ADC_TSMR_TSAV_Pos;\r
+       uint32_t ts_freq = (mode_reg & ADC_TSMR_TSFREQ_Msk) >> ADC_TSMR_TSFREQ_Pos;\r
+       if (ts_av) {\r
+               if (ts_av > ts_freq) {\r
+                       mode_reg &= ~ADC_TSMR_TSFREQ_Msk;\r
+                       mode_reg |= ADC_TSMR_TSFREQ(ts_av);\r
+               }\r
+       }\r
+       ADC->ADC_TSMR = mode_reg | avg_2_conv;\r
+}\r
+\r
+uint32_t adc_get_ts_xposition(void)\r
+{\r
+       return ADC->ADC_XPOSR;\r
+}\r
+\r
+uint32_t adc_get_ts_yposition(void)\r
+{\r
+       return ADC->ADC_YPOSR;\r
+}\r
+\r
+uint32_t adc_get_ts_pressure(void)\r
+{\r
+       return ADC->ADC_PRESSR;\r
+}\r
+\r
+void adc_set_trigger(uint32_t trigger)\r
+{\r
+       uint32_t mode_reg;\r
+\r
+       mode_reg = ADC->ADC_MR;\r
+       mode_reg &= ~ADC_MR_TRGSEL_Msk;\r
+       mode_reg |= trigger;\r
+       ADC->ADC_MR |= mode_reg;\r
+}\r
+\r
+#ifdef CONFIG_HAVE_ADC_LOW_RES\r
+void adc_set_low_resolution(uint8_t enable)\r
+{\r
+       if (enable) {\r
+               ADC->ADC_MR |= ADC_MR_LOWRES;\r
+       } else {\r
+               ADC->ADC_MR &= ~ADC_MR_LOWRES;\r
+       }\r
+}\r
+#endif\r