1 /*
2  * Copyright (c) 2015 - 2025, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <nrfx.h>
35 
36 #if NRFX_CHECK(NRFX_LPCOMP_ENABLED)
37 
38 #include <nrfx_lpcomp.h>
39 #include "prs/nrfx_prs.h"
40 
41 #define NRFX_LOG_MODULE LPCOMP
42 #include <nrfx_log.h>
43 
44 #define EVT_TO_STR(event)                                         \
45     (event == NRF_LPCOMP_EVENT_READY ? "NRF_LPCOMP_EVENT_READY" : \
46     (event == NRF_LPCOMP_EVENT_DOWN  ? "NRF_LPCOMP_EVENT_DOWN"  : \
47     (event == NRF_LPCOMP_EVENT_UP    ? "NRF_LPCOMP_EVENT_UP"    : \
48     (event == NRF_LPCOMP_EVENT_CROSS ? "NRF_LPCOMP_EVENT_CROSS" : \
49                                        "UNKNOWN EVENT"))))
50 
51 static nrfx_lpcomp_event_handler_t  m_lpcomp_event_handler = NULL;
52 static nrfx_drv_state_t             m_state = NRFX_DRV_STATE_UNINITIALIZED;
53 
lpcomp_configure(nrfx_lpcomp_config_t const * p_config)54 static void lpcomp_configure(nrfx_lpcomp_config_t const * p_config)
55 {
56     nrfy_lpcomp_config_t nrfy_config =
57     {
58 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
59         .reference = p_config->reference,
60         .ext_ref   = p_config->ext_ref,
61         .detection = p_config->detection,
62         NRFX_COND_CODE_1(LPCOMP_FEATURE_HYST_PRESENT, (.hyst = p_config->config.hyst), ())
63 #else
64         .config =
65         {
66             .reference = p_config->config.reference,
67             .detection = p_config->config.detection,
68             NRFX_COND_CODE_1(LPCOMP_FEATURE_HYST_PRESENT, (.hyst = p_config->config.hyst), ())
69         },
70 #endif
71         .input = p_config->input
72     };
73 
74     nrfy_lpcomp_periph_configure(NRF_LPCOMP, &nrfy_config);
75 
76     uint32_t int_mask = 0;
77 
78 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
79     switch (p_config->detection)
80 #else
81     switch (p_config->config.detection)
82 #endif
83     {
84         case NRF_LPCOMP_DETECT_UP:
85             int_mask = NRF_LPCOMP_INT_UP_MASK;
86             break;
87 
88         case NRF_LPCOMP_DETECT_DOWN:
89             int_mask = NRF_LPCOMP_INT_DOWN_MASK;
90             break;
91 
92         case NRF_LPCOMP_DETECT_CROSS:
93             int_mask = NRF_LPCOMP_INT_CROSS_MASK;
94             break;
95 
96         default:
97             break;
98     }
99     nrfy_lpcomp_int_init(NRF_LPCOMP, int_mask, p_config->interrupt_priority, true);
100 }
101 
lpcomp_execute_handler(nrf_lpcomp_event_t event,uint32_t event_mask)102 static void lpcomp_execute_handler(nrf_lpcomp_event_t event, uint32_t event_mask)
103 {
104     if (event_mask & nrfy_lpcomp_int_enable_check(NRF_LPCOMP, NRFY_EVENT_TO_INT_BITMASK(event)))
105     {
106         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(event));
107 
108         m_lpcomp_event_handler(event);
109     }
110 }
111 
nrfx_lpcomp_irq_handler(void)112 void nrfx_lpcomp_irq_handler(void)
113 {
114     uint32_t evt_mask = nrfy_lpcomp_events_process(NRF_LPCOMP,
115                                                    NRF_LPCOMP_INT_READY_MASK |
116                                                    NRF_LPCOMP_INT_DOWN_MASK |
117                                                    NRF_LPCOMP_INT_UP_MASK |
118                                                    NRF_LPCOMP_INT_CROSS_MASK);
119 
120     lpcomp_execute_handler(NRF_LPCOMP_EVENT_READY, evt_mask);
121     lpcomp_execute_handler(NRF_LPCOMP_EVENT_DOWN,  evt_mask);
122     lpcomp_execute_handler(NRF_LPCOMP_EVENT_UP,    evt_mask);
123     lpcomp_execute_handler(NRF_LPCOMP_EVENT_CROSS, evt_mask);
124 }
125 
nrfx_lpcomp_init(nrfx_lpcomp_config_t const * p_config,nrfx_lpcomp_event_handler_t event_handler)126 nrfx_err_t nrfx_lpcomp_init(nrfx_lpcomp_config_t const * p_config,
127                             nrfx_lpcomp_event_handler_t  event_handler)
128 {
129     NRFX_ASSERT(p_config);
130     NRFX_ASSERT(event_handler);
131     nrfx_err_t err_code;
132 
133     if (m_state != NRFX_DRV_STATE_UNINITIALIZED)
134     { // LPCOMP driver is already initialized
135 #if NRFX_API_VER_AT_LEAST(3, 2, 0)
136         err_code = NRFX_ERROR_ALREADY;
137 #else
138         err_code = NRFX_ERROR_INVALID_STATE;
139 #endif
140         NRFX_LOG_WARNING("Function: %s, error code: %s.",
141                          __func__,
142                          NRFX_LOG_ERROR_STRING_GET(err_code));
143         return err_code;
144     }
145 
146     m_lpcomp_event_handler = event_handler;
147 
148 #if NRFX_CHECK(NRFX_PRS_ENABLED)
149     if (nrfx_prs_acquire(NRF_LPCOMP, nrfx_lpcomp_irq_handler) != NRFX_SUCCESS)
150     {
151         err_code = NRFX_ERROR_BUSY;
152         NRFX_LOG_WARNING("Function: %s, error code: %s.",
153                          __func__,
154                          NRFX_LOG_ERROR_STRING_GET(err_code));
155         return err_code;
156     }
157 #endif
158     nrfy_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_STOP);
159     nrfy_lpcomp_disable(NRF_LPCOMP);
160 
161     nrfy_lpcomp_shorts_disable(NRF_LPCOMP,
162                                NRF_LPCOMP_SHORT_CROSS_STOP_MASK |
163                                NRF_LPCOMP_SHORT_UP_STOP_MASK |
164                                NRF_LPCOMP_SHORT_DOWN_STOP_MASK |
165                                NRF_LPCOMP_SHORT_READY_STOP_MASK |
166                                NRF_LPCOMP_SHORT_READY_SAMPLE_MASK);
167     nrfy_lpcomp_int_disable(NRF_LPCOMP,
168                             NRF_LPCOMP_INT_READY_MASK |
169                             NRF_LPCOMP_INT_DOWN_MASK |
170                             NRF_LPCOMP_INT_UP_MASK |
171                             NRF_LPCOMP_INT_CROSS_MASK);
172 
173     lpcomp_configure(p_config);
174 
175     nrfy_lpcomp_enable(NRF_LPCOMP);
176 
177     nrfy_lpcomp_shorts_enable(NRF_LPCOMP, NRF_LPCOMP_SHORT_READY_SAMPLE_MASK);
178 
179     m_state = NRFX_DRV_STATE_INITIALIZED;
180 
181     err_code = NRFX_SUCCESS;
182     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
183     return err_code;
184 }
185 
nrfx_lpcomp_reconfigure(nrfx_lpcomp_config_t const * p_config)186 nrfx_err_t nrfx_lpcomp_reconfigure(nrfx_lpcomp_config_t const * p_config)
187 {
188     NRFX_ASSERT(p_config);
189     nrfx_err_t err_code;
190 
191     if (m_state == NRFX_DRV_STATE_POWERED_ON)
192     {
193         err_code = NRFX_ERROR_BUSY;
194         NRFX_LOG_WARNING("Function: %s, error code: %s.",
195                          __func__,
196                          NRFX_LOG_ERROR_STRING_GET(err_code));
197         return err_code;
198     }
199     else if (m_state == NRFX_DRV_STATE_INITIALIZED)
200     {
201         nrfy_lpcomp_disable(NRF_LPCOMP);
202         lpcomp_configure(p_config);
203         nrfy_lpcomp_enable(NRF_LPCOMP);
204         return NRFX_SUCCESS;
205     }
206     else
207     {
208         NRFX_ASSERT(m_state == NRFX_DRV_STATE_UNINITIALIZED);
209 
210         err_code = NRFX_ERROR_INVALID_STATE;
211         NRFX_LOG_WARNING("Function: %s, error code: %s.",
212                          __func__,
213                          NRFX_LOG_ERROR_STRING_GET(err_code));
214         return err_code;
215     }
216 }
217 
nrfx_lpcomp_uninit(void)218 void nrfx_lpcomp_uninit(void)
219 {
220     NRFX_ASSERT(m_state != NRFX_DRV_STATE_UNINITIALIZED);
221     nrfy_lpcomp_int_uninit(NRF_LPCOMP);
222     nrfx_lpcomp_disable();
223 #if NRFX_CHECK(NRFX_PRS_ENABLED)
224     nrfx_prs_release(NRF_LPCOMP);
225 #endif
226     m_state = NRFX_DRV_STATE_UNINITIALIZED;
227     m_lpcomp_event_handler = NULL;
228     NRFX_LOG_INFO("Uninitialized.");
229 }
230 
nrfx_lpcomp_init_check(void)231 bool nrfx_lpcomp_init_check(void)
232 {
233     return (m_state != NRFX_DRV_STATE_UNINITIALIZED);
234 }
235 
nrfx_lpcomp_start(uint32_t lpcomp_evt_en_mask,uint32_t lpcomp_shorts_mask)236 void nrfx_lpcomp_start(uint32_t lpcomp_evt_en_mask, uint32_t lpcomp_shorts_mask)
237 {
238     NRFX_ASSERT(m_state == NRFX_DRV_STATE_INITIALIZED);
239     nrfy_lpcomp_enable(NRF_LPCOMP);
240     (void)nrfy_lpcomp_events_process(NRF_LPCOMP, lpcomp_evt_en_mask);
241     nrfy_lpcomp_int_enable(NRF_LPCOMP, lpcomp_evt_en_mask);
242     nrfy_lpcomp_shorts_enable(NRF_LPCOMP, lpcomp_shorts_mask);
243     m_state = NRFX_DRV_STATE_POWERED_ON;
244     nrfy_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_START);
245     NRFX_LOG_INFO("Enabled.");
246 }
247 
nrfx_lpcomp_stop(void)248 void nrfx_lpcomp_stop(void)
249 {
250     NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON);
251     nrfy_lpcomp_disable(NRF_LPCOMP);
252     nrfy_lpcomp_task_trigger(NRF_LPCOMP, NRF_LPCOMP_TASK_STOP);
253     nrfy_lpcomp_int_disable(NRF_LPCOMP,
254                             NRF_LPCOMP_INT_READY_MASK |
255                             NRF_LPCOMP_INT_DOWN_MASK |
256                             NRF_LPCOMP_INT_UP_MASK |
257                             NRF_LPCOMP_INT_CROSS_MASK);
258     m_state = NRFX_DRV_STATE_INITIALIZED;
259     NRFX_LOG_INFO("Disabled.");
260 }
261 
nrfx_lpcomp_sample(void)262 uint32_t nrfx_lpcomp_sample(void)
263 {
264     NRFX_ASSERT(m_state == NRFX_DRV_STATE_POWERED_ON);
265 
266     return nrfy_lpcomp_sample(NRF_LPCOMP);
267 }
268 
269 #endif // NRFX_CHECK(NRFX_LPCOMP_ENABLED)
270