1 /*
2  * Copyright (c) 2015 - 2023, 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_QDEC_ENABLED)
37 
38 #include <nrfx_qdec.h>
39 
40 #if !NRFX_FEATURE_PRESENT(NRFX_QDEC, _ENABLED)
41 #error "No enabled QDEC instances. Check <nrfx_config.h>."
42 #endif
43 
44 #include <haly/nrfy_gpio.h>
45 
46 #define NRFX_LOG_MODULE QDEC
47 #include <nrfx_log.h>
48 
49 #define EVT_TO_STR(event)                                             \
50     (event == NRF_QDEC_EVENT_SAMPLERDY ? "NRF_QDEC_EVENT_SAMPLERDY" : \
51     (event == NRF_QDEC_EVENT_REPORTRDY ? "NRF_QDEC_EVENT_REPORTRDY" : \
52     (event == NRF_QDEC_EVENT_ACCOF     ? "NRF_QDEC_EVENT_ACCOF"     : \
53                                          "UNKNOWN EVENT")))
54 
55 // Control block - driver instance local data.
56 typedef struct
57 {
58     nrfx_drv_state_t          state;
59     bool                      skip_gpio_cfg;
60     nrfx_qdec_event_handler_t handler;
61     void *                    p_context;
62 } qdec_control_block_t;
63 
64 static qdec_control_block_t m_cb[NRFX_QDEC_ENABLED_COUNT];
65 
qdec_configure(nrfx_qdec_t const * p_instance,nrfx_qdec_config_t const * p_config)66 static void qdec_configure(nrfx_qdec_t const *        p_instance,
67                            nrfx_qdec_config_t const * p_config)
68 {
69     if (!p_config->skip_gpio_cfg)
70     {
71         nrfy_gpio_cfg_input(p_config->psela, NRF_GPIO_PIN_NOPULL);
72         nrfy_gpio_cfg_input(p_config->pselb, NRF_GPIO_PIN_NOPULL);
73         if (p_config->pselled != NRF_QDEC_PIN_NOT_CONNECTED)
74         {
75             nrfy_gpio_cfg_input(p_config->pselled, NRF_GPIO_PIN_NOPULL);
76         }
77     }
78 
79     nrfy_qdec_config_t nrfy_config =
80     {
81         .reportper = p_config->reportper,
82         .sampleper = p_config->sampleper,
83         .pins = {
84             .a_pin   = p_config->psela,
85             .b_pin   = p_config->pselb,
86             .led_pin = p_config->pselled
87         },
88         .ledpre    = p_config->ledpre,
89         .ledpol    = p_config->ledpol,
90         .dbfen     = p_config->dbfen,
91         .skip_psel_cfg = p_config->skip_psel_cfg
92     };
93 
94     nrfy_qdec_periph_configure(p_instance->p_reg, &nrfy_config);
95     nrfy_qdec_shorts_enable(p_instance->p_reg, NRF_QDEC_SHORT_REPORTRDY_READCLRACC_MASK);
96 
97     uint32_t int_mask = NRF_QDEC_INT_ACCOF_MASK;
98 
99     if (p_config->reportper_inten)
100     {
101         int_mask |= NRF_QDEC_INT_REPORTRDY_MASK;
102     }
103     if (p_config->sample_inten)
104     {
105         int_mask |= NRF_QDEC_INT_SAMPLERDY_MASK;
106     }
107     nrfy_qdec_int_init(p_instance->p_reg, int_mask, p_config->interrupt_priority, true);
108 }
109 
nrfx_qdec_init(nrfx_qdec_t const * p_instance,nrfx_qdec_config_t const * p_config,nrfx_qdec_event_handler_t handler,void * p_context)110 nrfx_err_t nrfx_qdec_init(nrfx_qdec_t const *        p_instance,
111                           nrfx_qdec_config_t const * p_config,
112                           nrfx_qdec_event_handler_t  handler,
113                           void *                     p_context)
114 {
115     NRFX_ASSERT(p_instance);
116     NRFX_ASSERT(p_config);
117     NRFX_ASSERT(handler);
118 
119     qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
120 
121     nrfx_err_t err_code;
122 
123     if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
124     {
125         err_code = NRFX_ERROR_INVALID_STATE;
126         NRFX_LOG_WARNING("Function: %s, error code: %s.",
127                          __func__,
128                          NRFX_LOG_ERROR_STRING_GET(err_code));
129         return err_code;
130     }
131 
132     p_cb->handler = handler;
133     p_cb->p_context = p_context;
134 
135     if (p_config)
136     {
137         p_cb->skip_gpio_cfg = p_config->skip_gpio_cfg;
138         qdec_configure(p_instance, p_config);
139     }
140 
141     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
142 
143     err_code = NRFX_SUCCESS;
144     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
145     return err_code;
146 }
147 
nrfx_qdec_reconfigure(nrfx_qdec_t const * p_instance,nrfx_qdec_config_t const * p_config)148 nrfx_err_t nrfx_qdec_reconfigure(nrfx_qdec_t const *        p_instance,
149                                  nrfx_qdec_config_t const * p_config)
150 {
151     NRFX_ASSERT(p_config);
152     qdec_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
153 
154     if (p_cb->state == NRFX_DRV_STATE_UNINITIALIZED)
155     {
156         return NRFX_ERROR_INVALID_STATE;
157     }
158     if (p_cb->state == NRFX_DRV_STATE_POWERED_ON)
159     {
160         return NRFX_ERROR_BUSY;
161     }
162     qdec_configure(p_instance, p_config);
163     nrfy_qdec_enable(p_instance->p_reg);
164     return NRFX_SUCCESS;
165 }
166 
nrfx_qdec_uninit(nrfx_qdec_t const * p_instance)167 void nrfx_qdec_uninit(nrfx_qdec_t const * p_instance)
168 {
169     NRFX_ASSERT(p_instance);
170     qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
171     nrfy_qdec_pins_t pins;
172 
173     NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
174 
175     nrfy_qdec_disable(p_instance->p_reg);
176     nrfy_qdec_int_uninit(p_instance->p_reg);
177 
178     nrfy_qdec_shorts_disable(p_instance->p_reg, NRF_QDEC_SHORT_REPORTRDY_READCLRACC_MASK);
179     if (!p_cb->skip_gpio_cfg)
180     {
181         nrfy_qdec_pins_get(p_instance->p_reg, &pins);
182         nrfy_gpio_cfg_default(pins.a_pin);
183         nrfy_gpio_cfg_default(pins.b_pin);
184 
185         uint32_t led_pin = nrfy_qdec_led_pin_get(p_instance->p_reg);
186         if (led_pin != NRF_QDEC_PIN_NOT_CONNECTED)
187         {
188             nrfy_gpio_cfg_default(led_pin);
189         }
190     }
191 
192     p_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
193     NRFX_LOG_INFO("Uninitialized.");
194 }
195 
nrfx_qdec_enable(nrfx_qdec_t const * p_instance)196 void nrfx_qdec_enable(nrfx_qdec_t const * p_instance)
197 {
198     NRFX_ASSERT(p_instance);
199 
200     qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
201 
202     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
203 
204     nrfy_qdec_enable(p_instance->p_reg);
205     nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_START);
206     p_cb->state = NRFX_DRV_STATE_POWERED_ON;
207     NRFX_LOG_INFO("Enabled.");
208 }
209 
nrfx_qdec_disable(nrfx_qdec_t const * p_instance)210 void nrfx_qdec_disable(nrfx_qdec_t const * p_instance)
211 {
212     NRFX_ASSERT(p_instance);
213 
214     qdec_control_block_t * const p_cb = &m_cb[p_instance->drv_inst_idx];
215 
216     NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_POWERED_ON);
217     nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_STOP);
218     nrfy_qdec_disable(p_instance->p_reg);
219     p_cb->state = NRFX_DRV_STATE_INITIALIZED;
220     NRFX_LOG_INFO("Disabled.");
221 }
222 
nrfx_qdec_accumulators_read(nrfx_qdec_t const * p_instance,int32_t * p_acc,uint32_t * p_accdbl)223 void nrfx_qdec_accumulators_read(nrfx_qdec_t const * p_instance,
224                                  int32_t *           p_acc,
225                                  uint32_t *          p_accdbl)
226 {
227     NRFX_ASSERT(p_instance);
228     NRFX_ASSERT(p_accdbl);
229     NRFX_ASSERT(p_acc);
230     NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_POWERED_ON);
231 
232     nrfy_qdec_task_trigger(p_instance->p_reg, NRF_QDEC_TASK_READCLRACC);
233     nrfy_qdec_accumulators_read(p_instance->p_reg, p_acc, p_accdbl);
234 
235     NRFX_LOG_DEBUG("Accumulators data, ACC register:");
236     NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_acc, sizeof(p_acc[0]));
237     NRFX_LOG_DEBUG("Accumulators data, ACCDBL register:");
238     NRFX_LOG_HEXDUMP_DEBUG((uint8_t *)p_accdbl, sizeof(p_accdbl[0]));
239 }
240 
irq_handler(NRF_QDEC_Type * p_qdec,qdec_control_block_t * p_cb)241 static void irq_handler(NRF_QDEC_Type * p_qdec, qdec_control_block_t * p_cb)
242 {
243     uint32_t evt_to_process;
244     nrfx_qdec_event_t event;
245     uint32_t evt_mask;
246 
247     evt_to_process = NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_SAMPLERDY) |
248                      NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_REPORTRDY) |
249                      NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_ACCOF);
250 
251     evt_mask = nrfy_qdec_events_process(p_qdec, evt_to_process);
252 
253     if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_SAMPLERDY))
254     {
255         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_SAMPLERDY));
256 
257         event.type = NRF_QDEC_EVENT_SAMPLERDY;
258         event.data.sample.value = (int8_t)nrfy_qdec_sample_get(p_qdec);
259         p_cb->handler(event, p_cb->p_context);
260     }
261 
262     if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_REPORTRDY))
263     {
264         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_REPORTRDY));
265 
266         event.type = NRF_QDEC_EVENT_REPORTRDY;
267         nrfy_qdec_accumulators_read(p_qdec, &event.data.report.acc, &event.data.report.accdbl);
268         p_cb->handler(event, p_cb->p_context);
269     }
270 
271     if (evt_mask & NRFY_EVENT_TO_INT_BITMASK(NRF_QDEC_EVENT_ACCOF))
272     {
273         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_QDEC_EVENT_ACCOF));
274 
275         event.type = NRF_QDEC_EVENT_ACCOF;
276         p_cb->handler(event, p_cb->p_context);
277     }
278 }
279 
280 NRFX_INSTANCE_IRQ_HANDLERS(QDEC, qdec)
281 
282 #endif // NRFX_CHECK(NRFX_QDEC_ENABLED)
283