|
30 | 30 | #include <pinctrl_soc.h> |
31 | 31 | #endif |
32 | 32 |
|
| 33 | +#if IS_ENABLED(CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_COMPENSATION) |
| 34 | +#include <protocol/mpsl_fem_nrf2220_protocol_api.h> |
| 35 | +#include <zephyr/drivers/i2c/i2c_nrfx_twim.h> |
| 36 | +#endif |
| 37 | + |
33 | 38 | #if !defined(CONFIG_PINCTRL) |
34 | 39 | #error "The nRF2220 driver must be used with CONFIG_PINCTRL! Set CONFIG_PINCTRL=y" |
35 | 40 | #endif |
@@ -66,7 +71,15 @@ static void fem_nrf2220_twi_init_regs_configure(mpsl_fem_nrf2220_interface_confi |
66 | 71 |
|
67 | 72 | static void fem_nrf2220_twi_configure(mpsl_fem_nrf2220_interface_config_t *cfg) |
68 | 73 | { |
69 | | - cfg->twi_if = MPSL_FEM_TWI_DRV_IF_INITIALIZER(MPSL_FEM_TWI_IF); |
| 74 | + if (IS_ENABLED(CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_COMPENSATION_WITH_MPSL_SCHEDULER)) { |
| 75 | + /* The nRF2220 temperature compensation with the MPSL scheduler requires |
| 76 | + * asynchronous interface. |
| 77 | + * See mpsl_fem_nrf2220_temperature_changed_update_request function. |
| 78 | + */ |
| 79 | + cfg->twi_if = MPSL_FEM_TWI_DRV_IF_INITIALIZER_WASYNC(MPSL_FEM_TWI_IF); |
| 80 | + } else { |
| 81 | + cfg->twi_if = MPSL_FEM_TWI_DRV_IF_INITIALIZER(MPSL_FEM_TWI_IF); |
| 82 | + } |
70 | 83 | } |
71 | 84 | #endif /* DT_NODE_HAS_PROP(DT_NODELABEL(nrf_radio_fem), twi_if) */ |
72 | 85 |
|
@@ -193,4 +206,145 @@ BUILD_ASSERT(CONFIG_MPSL_FEM_INIT_PRIORITY > CONFIG_I2C_INIT_PRIORITY, |
193 | 206 |
|
194 | 207 | SYS_INIT(mpsl_fem_init, POST_KERNEL, CONFIG_MPSL_FEM_INIT_PRIORITY); |
195 | 208 |
|
| 209 | +#if defined(CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_COMPENSATION) |
| 210 | + |
| 211 | +static K_SEM_DEFINE(fem_temperature_new_value_sem, 0, 1); |
| 212 | + |
| 213 | +#if defined(CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_COMPENSATION_WITH_MPSL_SCHEDULER) |
| 214 | +static int32_t fem_temperature_update_result; |
| 215 | +static K_SEM_DEFINE(fem_temperature_updated_cb_sem, 0, 1); |
| 216 | + |
| 217 | +static void fem_temperature_update_cb(int32_t res) |
| 218 | +{ |
| 219 | + fem_temperature_update_result = res; |
| 220 | + k_sem_give(&fem_temperature_updated_cb_sem); |
| 221 | +} |
| 222 | + |
| 223 | +static int32_t fem_temperature_changed_update_now(void) |
| 224 | +{ |
| 225 | + const struct device *i2c_bus_dev = DEVICE_DT_GET(DT_BUS(MPSL_FEM_TWI_IF)); |
| 226 | + |
| 227 | + /* Let's have initially "taken" semaphore that will inform the operation |
| 228 | + * on the nrf2220 is finished. |
| 229 | + */ |
| 230 | + k_sem_take(&fem_temperature_updated_cb_sem, K_NO_WAIT); |
| 231 | + |
| 232 | + (void)i2c_nrfx_twim_exclusive_access_acquire(i2c_bus_dev, K_FOREVER); |
| 233 | + |
| 234 | + /* Temporary raise i2c_bus_dev IRQ priority, as required by the |
| 235 | + * mpsl_fem_nrf2220_temperature_changed_update_request function. |
| 236 | + * The IRQs from i2c may not be delayed while performing operations |
| 237 | + * in a timeslot granted by the MPSL scheduler. |
| 238 | + */ |
| 239 | + z_arm_irq_priority_set(DT_IRQN(DT_BUS(MPSL_FEM_TWI_IF)), 0, IRQ_ZERO_LATENCY); |
| 240 | + |
| 241 | + mpsl_fem_nrf2220_temperature_changed_update_request(fem_temperature_update_cb); |
| 242 | + |
| 243 | + /* Let's wait until the operation is finished */ |
| 244 | + k_sem_take(&fem_temperature_updated_cb_sem, K_FOREVER); |
| 245 | + |
| 246 | + /* Restore original i2c_bus_dev IRQ priority. */ |
| 247 | + z_arm_irq_priority_set(DT_IRQN(DT_BUS(MPSL_FEM_TWI_IF)), |
| 248 | + DT_IRQ(DT_BUS(MPSL_FEM_TWI_IF), priority), 0); |
| 249 | + |
| 250 | + i2c_nrfx_twim_exclusive_access_release(i2c_bus_dev); |
| 251 | + |
| 252 | + return fem_temperature_update_result; |
| 253 | +} |
| 254 | +#endif /* CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_COMPENSATION_MPSL_SCHEDULER */ |
| 255 | + |
| 256 | +#if defined(CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_SOURCE_SOC) |
| 257 | + |
| 258 | +#include <zephyr/drivers/sensor.h> |
| 259 | +#define FEM_TEMPERATURE_NEW_VALUE_SEM_TIMEOUT \ |
| 260 | + (K_MSEC(CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_POLL_PERIOD)) |
| 261 | + |
| 262 | +static int8_t fem_temperature_sensor_value_get(void) |
| 263 | +{ |
| 264 | + const struct device *dev = DEVICE_DT_GET_ONE(nordic_nrf_temp); |
| 265 | + |
| 266 | + if (!device_is_ready(dev)) { |
| 267 | + __ASSERT(false, "Temperature sensor not ready"); |
| 268 | + } |
| 269 | + |
| 270 | + struct sensor_value v; |
| 271 | + int ret = sensor_sample_fetch(dev); |
| 272 | + |
| 273 | + __ASSERT(ret == 0, "Can't fetch temperature sensor sample"); |
| 274 | + |
| 275 | + ret = sensor_channel_get(dev, SENSOR_CHAN_DIE_TEMP, &v); |
| 276 | + __ASSERT(ret == 0, "Can't get temperature of the die"); |
| 277 | + |
| 278 | + (void)ret; |
| 279 | + |
| 280 | + return v.val1; |
| 281 | +} |
| 282 | +#endif /* CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_SOURCE_SOC */ |
| 283 | + |
| 284 | +#if defined(CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_SOURCE_CUSTOM) |
| 285 | + |
| 286 | +#define FEM_TEMPERATURE_NEW_VALUE_SEM_TIMEOUT K_FOREVER |
| 287 | + |
| 288 | +#define NRF2220_TEMPERATURE_DEFAULT 25 |
| 289 | + |
| 290 | +static int8_t fem_temperature_value = NRF2220_TEMPERATURE_DEFAULT; |
| 291 | + |
| 292 | +void fem_temperature_change(int8_t temperature) |
| 293 | +{ |
| 294 | + fem_temperature_value = temperature; |
| 295 | + k_sem_give(&fem_temperature_new_value_sem); |
| 296 | +} |
| 297 | + |
| 298 | +static int8_t fem_temperature_sensor_value_get(void) |
| 299 | +{ |
| 300 | + return fem_temperature_value; |
| 301 | +} |
| 302 | +#endif /* CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_SOURCE_CUSTOM */ |
| 303 | + |
| 304 | +static void fem_temperature_compensation_thread(void *dummy1, void *dummy2, void *dummy3) |
| 305 | +{ |
| 306 | + ARG_UNUSED(dummy1); |
| 307 | + ARG_UNUSED(dummy2); |
| 308 | + ARG_UNUSED(dummy3); |
| 309 | + |
| 310 | + while (true) { |
| 311 | + (void)k_sem_take(&fem_temperature_new_value_sem, |
| 312 | + FEM_TEMPERATURE_NEW_VALUE_SEM_TIMEOUT); |
| 313 | + |
| 314 | + int8_t new_temperature = fem_temperature_sensor_value_get(); |
| 315 | + |
| 316 | + if (mpsl_fem_nrf2220_temperature_changed(new_temperature)) { |
| 317 | +#if defined(CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_COMPENSATION_WITH_MPSL_SCHEDULER) |
| 318 | + int32_t res = fem_temperature_changed_update_now(); |
| 319 | + |
| 320 | + __ASSERT(res == 0, "FEM update on temperature change failed"); |
| 321 | + (void)res; |
| 322 | +#endif /* CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_COMPENSATION_WITH_MPSL_SCHEDULER */ |
| 323 | + } |
| 324 | + } |
| 325 | +} |
| 326 | + |
| 327 | +#define FEM_TEMPERATURE_COMPENSATION_THREAD_STACK_SIZE 512 |
| 328 | + |
| 329 | +static K_THREAD_STACK_DEFINE(fem_temperature_compensation_thread_stack, |
| 330 | + FEM_TEMPERATURE_COMPENSATION_THREAD_STACK_SIZE); |
| 331 | +static struct k_thread fem_temperature_compensation_thread_data; |
| 332 | + |
| 333 | +static int fem_nrf2220_temperature_compensation_init(void) |
| 334 | +{ |
| 335 | + (void)k_thread_create(&fem_temperature_compensation_thread_data, |
| 336 | + fem_temperature_compensation_thread_stack, |
| 337 | + K_THREAD_STACK_SIZEOF(fem_temperature_compensation_thread_stack), |
| 338 | + fem_temperature_compensation_thread, |
| 339 | + NULL, NULL, NULL, |
| 340 | + K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT); |
| 341 | + |
| 342 | + return 0; |
| 343 | +} |
| 344 | + |
| 345 | +SYS_INIT(fem_nrf2220_temperature_compensation_init, APPLICATION, |
| 346 | + CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |
| 347 | + |
| 348 | +#endif /* CONFIG_MPSL_FEM_NRF2220_TEMPERATURE_COMPENSATION */ |
| 349 | + |
196 | 350 | #endif /* defined(CONFIG_MPSL_FEM_NRF2220) */ |
0 commit comments