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