1 /*
2  * Copyright 2024 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_sdadc.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.sdadc"
16 #endif
17 
18 /*******************************************************************************
19  * Prototypes
20  ******************************************************************************/
21 
22 /*******************************************************************************
23  * Variables
24  ******************************************************************************/
25 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
26 /*! @brief Pointers to SDADC bases for each instance. */
27 #if defined(SDADC_BASE_PTRS_NS)
28 static SDADC_Type *s_sdadcBases_ns[] = SDADC_BASE_PTRS_NS;
29 #endif /* SDADC_BASE_PTRS_NS */
30 static SDADC_Type *s_sdadcBases[] = SDADC_BASE_PTRS;
31 
32 /*! @brief Pointers to SDADC clocks for each instance. */
33 static const clock_ip_name_t s_sdadcClocks[] = SDADC_CLOCKS;
34 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
35 
36 /*! @brief SDADC reset array for each instance. */
37 #if defined(SDADC_RSTS)
38 static const reset_ip_name_t s_sdadcResets[] = SDADC_RSTS;
39 #endif                                    /* SDADC_RSTS */
40 
41 static char sdadcChannelModeRecord = 'D'; /* Record the conversion mode used by the SDADC channel
42                                           in the initialization state, by default, it is set to 'D',
43                                           which means only differential mode is executed. */
44 /*******************************************************************************
45  * Code
46  ******************************************************************************/
47 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
48 /*!
49  * brief This function is used to get the SDADC instance.
50  *
51  * param base SDADC peripheral base address.
52  *
53  * return SDADC instance.
54  */
SDADC_GetInstance(SDADC_Type * base)55 static uint32_t SDADC_GetInstance(SDADC_Type *base)
56 {
57     uint32_t instance             = 0U;
58     uint8_t sdadcBaseSize         = ARRAY_SIZE(s_sdadcBases);
59     SDADC_Type **sdadcBaseAddress = s_sdadcBases;
60 
61 #if defined(SDADC_BASE_PTRS_NS)
62     if (0U == ((uint32_t)base & 0x10000000U))
63     {
64         /* Input instance is in the non-secure area. */
65         sdadcBaseSize    = ARRAY_SIZE(s_sdadcBases_ns);
66         sdadcBaseAddress = s_sdadcBases_ns;
67     }
68 #endif /* SDADC_BASE_PTRS_NS */
69 
70     /* Find the instance index from base address mappings. */
71     for (; instance < sdadcBaseSize; ++instance)
72     {
73         if (sdadcBaseAddress[instance] == base)
74         {
75             break;
76         }
77     }
78 
79     assert(instance < sdadcBaseSize);
80 
81     return instance;
82 }
83 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
84 
85 /*!
86  * brief This function is used to get available predefined configurations for the SDADC initialization.
87  *
88  * param config Pointer to the SDADC configuration structure, please refer to @ref sdadc_config_t for details.
89  */
SDADC_GetDefaultConfig(sdadc_config_t * config)90 void SDADC_GetDefaultConfig(sdadc_config_t *config)
91 {
92     assert(config != NULL);
93 
94     config->channelCount  = 0U;
95     config->channelConfig = NULL;
96 }
97 
98 /*!
99  * brief This function is used to initialize the SDADC.
100  *
101  * param base SDADC peripheral base address.
102  * param config Pointer to the SDADC configuration structure, please refer to @ref sdadc_config_t for details.
103  */
SDADC_Init(SDADC_Type * base,const sdadc_config_t * config)104 void SDADC_Init(SDADC_Type *base, const sdadc_config_t *config)
105 {
106     assert(config != NULL);
107 
108 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
109     /* Enable the clock for the SDADC instance. */
110     (void)CLOCK_EnableClock(s_sdadcClocks[SDADC_GetInstance(base)]);
111 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
112 
113 #if defined(SDADC_RSTS)
114     /* Release the SDADC reset. */
115     RESET_ReleasePeripheralReset(s_sdadcResets[SDADC_GetInstance(base)]);
116 #endif /* SDADC_RSTS */
117 
118     sdadc_channel_config_t *channelConfig = config->channelConfig;
119 
120     for (uint8_t index = 0U; index < config->channelCount; ++index)
121     {
122         SDADC_ConfigureChannelMode(base, channelConfig->number, channelConfig->mode);
123 
124         if (kSDADC_SingleEnd_Mode == channelConfig->mode)
125         {
126             sdadcChannelModeRecord = 'S'; /* If there is a single-end mode conversion, mark it as 'S'. */
127 
128             /*! Configure DAC compensation. */
129             SDADC_ControlDacCompensationEnable(base, channelConfig->number, channelConfig->type,
130                                                channelConfig->enableDacCompensation);
131             /*! Configure DC Loop. */
132             SDADC_ControlModulatorDcLoopEnable(base, channelConfig->number, channelConfig->type,
133                                                channelConfig->enableDCLoop);
134         }
135         else
136         {
137             /*! Disable DAC compensation. */
138             SDADC_ControlDacCompensationEnable(base, channelConfig->number, channelConfig->type, false);
139             /*! Disable DC Loop. */
140             SDADC_ControlModulatorDcLoopEnable(base, channelConfig->number, channelConfig->type, false);
141         }
142 
143         /*! Decimator DC Filter configuration. */
144         SDADC_ControlDecimatorDcFilterEnable(base, channelConfig->number, channelConfig->type,
145                                              channelConfig->enableDcFilter);
146         /*! Decimator output signal invert configuration. */
147         SDADC_ControlDecimatorOutputInvertEnable(base, channelConfig->number, channelConfig->type,
148                                                  channelConfig->enablePolarityInvert);
149 
150         /*! Configure channel volume (gain). */
151         SDADC_ConfigureDecimatorVolume(base, channelConfig->number, channelConfig->type, channelConfig->volume);
152         /*! Configure decimator sample rate. */
153         SDADC_ConfigureDecimatorSampleRate(base, channelConfig->number, channelConfig->type, channelConfig->samplerate);
154         /*! Configure FIFO watermark. */
155         SDADC_ConfigureFifoWatermark(base, channelConfig->number, channelConfig->type, channelConfig->watermark);
156 
157         channelConfig += 1U;
158     }
159 }
160 
161 /*!
162  * brief This function is used to power up the ADC in the initialization state.
163  *
164  * param base SDADC peripheral base address.
165  * param config Pointer to the SDADC configuration structure, please refer to @ref sdadc_config_t for details.
166  * param clock Core clock frequency with Hz.
167  */
SDADC_DoInitPowerUp(SDADC_Type * base,sdadc_config_t * config,uint32_t clock)168 void SDADC_DoInitPowerUp(SDADC_Type *base, sdadc_config_t *config, uint32_t clock)
169 {
170     /*! Enable reference power, set the reference mode to fast charge mode at the beginning, delay 1ms waiting for the
171         reference power up then set the reference mode to retain mode (when there is only differential mode executing)
172         or set to the low noise mode (when there is a single-end mode executing).
173     */
174     SDADC_ControlReferencePowerEnable(base, true);
175     SDADC_ConfigureReferenceMode(base, kSDADC_RefFastChargeMode);
176     SDK_DelayAtLeastUs(1000U, clock);
177 
178     if ('S' == sdadcChannelModeRecord) /* If only single end mode enabled, entry low noise mode to reduce noise. */
179     {
180         SDADC_ConfigureReferenceMode(base, kSDADC_RefLowNoiseMode);
181     }
182     else /* If there is no single end mode enabled, entry retain mode to save power. */
183     {
184         SDADC_ConfigureReferenceMode(base, kSDADC_RefRetainMode);
185     }
186 
187     /*! Enable LDO power and set LDO drive capability. */
188     SDADC_ControlLdoPowerEnable(base, true);
189     if (config->channelCount <= 1U)
190     {
191         SDADC_ConfigureLdoDriveCapability(base, kSDADC_LdoLowPower);
192     }
193     else
194     {
195         SDADC_ConfigureLdoDriveCapability(base, kSDADC_LdoHighPower);
196     }
197 
198     /*! Enable conversion channel's modulator power. */
199     for (uint8_t index = 0U; index < config->channelCount; ++index)
200     {
201         SDADC_ControlModulatorPowerEnable(base, (config->channelConfig + index)->number,
202                                           (config->channelConfig + index)->type, true);
203     }
204 
205     /*! Reset the SDADC channel P-Side or/and N-Side 15us to avoid saturation behavior. */
206     for (uint8_t index = 0U; index < config->channelCount; ++index)
207     {
208         SDADC_ControlModulatorReset(base, (config->channelConfig + index)->number,
209                                     (config->channelConfig + index)->type, true);
210     }
211 
212     SDK_DelayAtLeastUs(50U, clock);
213 
214     for (uint8_t index = 0U; index < config->channelCount; ++index)
215     {
216         SDADC_ControlModulatorReset(base, (config->channelConfig + index)->number,
217                                     (config->channelConfig + index)->type, false);
218     }
219 }
220 
221 /*!
222  * brief This function is used to de-initialize the SDADC.
223  *
224  * param base SDADC peripheral base address.
225  */
SDADC_Deinit(SDADC_Type * base,const sdadc_config_t * config)226 void SDADC_Deinit(SDADC_Type *base, const sdadc_config_t *config)
227 {
228     /*! Disable SDADC channels power. */
229     for (uint8_t index = 0U; index < config->channelCount; ++index)
230     {
231         SDADC_ControlModulatorPowerEnable(base, (config->channelConfig + index)->number,
232                                           (config->channelConfig + index)->type, false);
233     }
234 
235     base->ADC_CTL_0 &= (~(SDADC_ADC_CTL_0_ADCP_POWER_ENABLE_MASK | SDADC_ADC_CTL_0_ADCN_POWER_ENABLE_MASK));
236     /*! Disable the LDO power. */
237     SDADC_ControlLdoPowerEnable(base, false);
238     /*! Disable the reference power. */
239     SDADC_ControlReferencePowerEnable(base, false);
240 
241 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
242     /*! Disable the clock gate. */
243     CLOCK_DisableClock(s_sdadcClocks[SDADC_GetInstance(base)]);
244 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
245 
246 #if defined(SDADC_RSTS)
247     RESET_PeripheralReset(s_sdadcResets[SDADC_GetInstance(base)]);
248 #endif /* SDADC_RSTS */
249 }
250 
251 /*!
252  * brief This function is used to copy specific conversion channels' data from FIFO to buffer.
253  *
254  * note This function will copy all 16 entries in the specified FIFO.
255  *
256  * param base SDADC peripheral base address.
257  * param group Indicates which group of channels data to obtain.
258  * param count Indicates how many channels in the specified group.
259  * param buffer The buffer which stores conversion data.
260  */
SDADC_CopyConvChannelFifoToBuffer(SDADC_Type * base,sdadc_channel_group * group,uint8_t count,void * buffer)261 void SDADC_CopyConvChannelFifoToBuffer(SDADC_Type *base, sdadc_channel_group *group, uint8_t count, void *buffer)
262 {
263     uint32_t *dataAddr = (uint32_t *)buffer;
264 
265     for (uint8_t fifoItemIndex = 0U; fifoItemIndex < SDADC_FIFO_DEPTH; fifoItemIndex++)
266     {
267         for (uint8_t fifoIndex = 0; fifoIndex < count; fifoIndex++)
268         {
269             *dataAddr = SDADC_GetConvChannelFifoRawData(base, (group + fifoIndex)->number, (group + fifoIndex)->type);
270             dataAddr  = (uint32_t *)((uint32_t)dataAddr + SDADC_FIFO_WIDTH);
271         }
272     }
273 }
274