1 /*
2  * Copyright (c) 2020, 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 Nordic Semiconductor ASA 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 
35 #include <nrfx.h>
36 #include "nrf_errno.h"
37 #include <stdbool.h>
38 #include <stdint.h>
39 
40 #include "nrf_802154_fal.h"
41 #include "nrf_802154_types.h"
42 
43 #include "mpsl_tx_power.h"
44 #include "protocol/mpsl_fem_protocol_api.h"
45 
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49 
50 /**@brief Macro to get the number of elements in an array.
51  *
52  * @param[in] X   Array.
53  */
54 #define NUMELTS(X) (sizeof((X)) / sizeof(X[0]))
55 
56 typedef struct
57 {
58     nrf_radio_txpower_t reg;
59     int8_t              dbm;
60 } radio_tx_power_t;
61 
62 /**
63  * Converts TX power integer values to RADIO TX power allowed values.
64  *
65  * @param[in]  integer_tx_power  TX power integer value.
66  *
67  * @retval     RADIO TX power allowed value.
68  */
to_radio_tx_power_convert(int8_t integer_tx_power)69 static radio_tx_power_t to_radio_tx_power_convert(int8_t integer_tx_power)
70 {
71     static const radio_tx_power_t allowed_values[] =
72     {
73 #if defined(RADIO_TXPOWER_TXPOWER_Neg40dBm)
74         { NRF_RADIO_TXPOWER_NEG40DBM, -40 }, /**< -40 dBm. */
75 #endif
76         { NRF_RADIO_TXPOWER_NEG20DBM, -20 }, /**< -20 dBm. */
77         { NRF_RADIO_TXPOWER_NEG16DBM, -16 }, /**< -16 dBm. */
78         { NRF_RADIO_TXPOWER_NEG12DBM, -12 }, /**< -12 dBm. */
79         { NRF_RADIO_TXPOWER_NEG8DBM, -8 },   /**< -8 dBm. */
80         { NRF_RADIO_TXPOWER_NEG4DBM, -4 },   /**< -4 dBm. */
81         { NRF_RADIO_TXPOWER_0DBM, 0 },       /**< 0 dBm. */
82 #if defined(NRF53_SERIES)
83         { NRF_RADIO_TXPOWER_NEG2DBM, 1 },    /**< 1 dBm. */
84         { NRF_RADIO_TXPOWER_NEG1DBM, 2 },    /**< 2 dBm. */
85         { NRF_RADIO_TXPOWER_0DBM, 3 },       /**< 3 dBm. */
86 #endif
87 #if defined(RADIO_TXPOWER_TXPOWER_Pos2dBm)
88         { NRF_RADIO_TXPOWER_POS2DBM, 2 },    /**< 2 dBm. */
89 #endif
90 #if defined(RADIO_TXPOWER_TXPOWER_Pos3dBm)
91         { NRF_RADIO_TXPOWER_POS3DBM, 3 },    /**< 3 dBm. */
92 #endif
93 #if defined(RADIO_TXPOWER_TXPOWER_Pos4dBm)
94         { NRF_RADIO_TXPOWER_POS4DBM, 4 },    /**< 4 dBm. */
95 #endif
96 #if defined(RADIO_TXPOWER_TXPOWER_Pos5dBm)
97         { NRF_RADIO_TXPOWER_POS5DBM, 5 },    /**< 5 dBm. */
98 #endif
99 #if defined(RADIO_TXPOWER_TXPOWER_Pos6dBm)
100         { NRF_RADIO_TXPOWER_POS6DBM, 6 },    /**< 6 dBm. */
101 #endif
102 #if defined(RADIO_TXPOWER_TXPOWER_Pos7dBm)
103         { NRF_RADIO_TXPOWER_POS7DBM, 7 },    /**< 7 dBm. */
104 #endif
105 #if defined(RADIO_TXPOWER_TXPOWER_Pos8dBm)
106         { NRF_RADIO_TXPOWER_POS8DBM, 8 },    /**< 8 dBm. */
107 #endif
108     };
109 
110     for (uint32_t i = NUMELTS(allowed_values) - 1; i > 0; i--)
111     {
112         if (integer_tx_power >= allowed_values[i].dbm)
113         {
114             return allowed_values[i];
115         }
116     }
117 
118     return allowed_values[0];
119 }
120 
mpsl_fem_caps_get(mpsl_fem_caps_t * p_caps)121 void mpsl_fem_caps_get(mpsl_fem_caps_t * p_caps)
122 {
123     *p_caps = (mpsl_fem_caps_t){};
124 }
125 
mpsl_fem_enable(void)126 void mpsl_fem_enable(void)
127 {
128     // Intentionally empty
129 }
130 
mpsl_fem_disable(void)131 int32_t mpsl_fem_disable(void)
132 {
133     return 0;
134 }
135 
mpsl_fem_pa_configuration_set(const mpsl_fem_event_t * const p_activate_event,const mpsl_fem_event_t * const p_deactivate_event)136 int32_t mpsl_fem_pa_configuration_set(const mpsl_fem_event_t * const p_activate_event,
137                                       const mpsl_fem_event_t * const p_deactivate_event)
138 {
139     (void)p_activate_event;
140     (void)p_deactivate_event;
141 
142     return -NRF_EPERM;
143 }
144 
mpsl_fem_pa_configuration_clear(void)145 int32_t mpsl_fem_pa_configuration_clear(void)
146 {
147     return -NRF_EPERM;
148 }
149 
mpsl_fem_lna_configuration_set(const mpsl_fem_event_t * const p_activate_event,const mpsl_fem_event_t * const p_deactivate_event)150 int32_t mpsl_fem_lna_configuration_set(const mpsl_fem_event_t * const p_activate_event,
151                                        const mpsl_fem_event_t * const p_deactivate_event)
152 {
153     (void)p_activate_event;
154     (void)p_deactivate_event;
155 
156     return -NRF_EPERM;
157 }
158 
mpsl_fem_lna_configuration_clear(void)159 int32_t mpsl_fem_lna_configuration_clear(void)
160 {
161     return -NRF_EPERM;
162 }
163 
mpsl_fem_deactivate_now(mpsl_fem_functionality_t type)164 void mpsl_fem_deactivate_now(mpsl_fem_functionality_t type)
165 {
166     (void)type;
167 }
168 
mpsl_fem_abort_set(mpsl_subscribable_hw_event_t event,uint32_t group)169 int32_t mpsl_fem_abort_set(mpsl_subscribable_hw_event_t event, uint32_t group)
170 {
171     return -NRF_EPERM;
172 }
173 
mpsl_fem_abort_extend(uint32_t channel_to_add,uint32_t group)174 int32_t mpsl_fem_abort_extend(uint32_t channel_to_add, uint32_t group)
175 {
176     (void)channel_to_add;
177     (void)group;
178     return 0;
179 }
180 
mpsl_fem_abort_reduce(uint32_t channel_to_remove,uint32_t group)181 int32_t mpsl_fem_abort_reduce(uint32_t channel_to_remove, uint32_t group)
182 {
183     (void)channel_to_remove;
184     (void)group;
185     return 0;
186 }
187 
mpsl_fem_abort_clear(void)188 int32_t mpsl_fem_abort_clear(void)
189 {
190     return -NRF_EPERM;
191 }
192 
mpsl_fem_cleanup(void)193 void mpsl_fem_cleanup(void)
194 {
195     // Intentionally empty
196 }
197 
mpsl_fem_tx_power_split(const mpsl_tx_power_t power,mpsl_tx_power_split_t * const p_tx_power_split,uint16_t freq_mhz,bool tx_power_ceiling)198 int8_t mpsl_fem_tx_power_split(const mpsl_tx_power_t         power,
199                                mpsl_tx_power_split_t * const p_tx_power_split,
200                                uint16_t                      freq_mhz,
201                                bool                          tx_power_ceiling)
202 {
203     (void)freq_mhz;
204     (void)tx_power_ceiling;
205 
206     p_tx_power_split->radio_tx_power       = to_radio_tx_power_convert(power).dbm;
207     p_tx_power_split->fem_pa_power_control = 0;
208 
209     return p_tx_power_split->radio_tx_power;
210 }
211 
mpsl_fem_pa_power_control_set(mpsl_fem_pa_power_control_t pa_power_control)212 int32_t mpsl_fem_pa_power_control_set(mpsl_fem_pa_power_control_t pa_power_control)
213 {
214     (void)pa_power_control;
215 
216     return 0;
217 }
218 
mpsl_fem_prepare_powerdown(NRF_TIMER_Type * p_instance,uint32_t compare_channel,uint32_t ppi_id,uint32_t event_addr)219 bool mpsl_fem_prepare_powerdown(NRF_TIMER_Type * p_instance,
220                                 uint32_t         compare_channel,
221                                 uint32_t         ppi_id,
222                                 uint32_t         event_addr)
223 {
224     (void)p_instance;
225     (void)compare_channel;
226     (void)ppi_id;
227 
228     return false;
229 }
230 
mpsl_fem_device_config_254_apply_get(void)231 bool mpsl_fem_device_config_254_apply_get(void)
232 {
233     return false;
234 }
235 
nrf_802154_fal_tx_power_split(const uint8_t channel,const int8_t power,nrf_802154_fal_tx_power_split_t * const p_tx_power_split)236 int8_t nrf_802154_fal_tx_power_split(const uint8_t                           channel,
237                                      const int8_t                            power,
238                                      nrf_802154_fal_tx_power_split_t * const p_tx_power_split)
239 {
240     (void)channel;
241 
242     p_tx_power_split->radio_tx_power       = to_radio_tx_power_convert(power).dbm;
243     p_tx_power_split->fem_pa_power_control = 0;
244 
245     return p_tx_power_split->radio_tx_power;
246 }
247 
mpsl_tx_power_dbm_to_radio_register_convert(mpsl_tx_power_t req_radio_power)248 uint32_t mpsl_tx_power_dbm_to_radio_register_convert(mpsl_tx_power_t req_radio_power)
249 {
250     return to_radio_tx_power_convert(req_radio_power).reg;
251 }
252 
253 #ifdef __cplusplus
254 }
255 #endif
256