/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include "syscfg/syscfg.h" #include "os/os_cputime.h" #include "controller/ble_phy.h" #include "controller/ble_ll.h" #include "controller/ble_ll_xcvr.h" #ifdef BLE_XCVR_RFCLK int ble_ll_xcvr_rfclk_state(void) { uint32_t expiry; if (g_ble_ll_data.ll_rfclk_state == BLE_RFCLK_STATE_ON) { expiry = g_ble_ll_data.ll_rfclk_start_time; if ((int32_t)(os_cputime_get32() - expiry) > g_ble_ll_data.ll_xtal_ticks) { g_ble_ll_data.ll_rfclk_state = BLE_RFCLK_STATE_SETTLED; } } return g_ble_ll_data.ll_rfclk_state; } void ble_ll_xcvr_rfclk_enable(void) { if (g_ble_ll_data.ll_rfclk_state == BLE_RFCLK_STATE_OFF) { g_ble_ll_data.ll_rfclk_state = BLE_RFCLK_STATE_ON; ble_phy_rfclk_enable(); } } void ble_ll_xcvr_rfclk_disable(void) { if (g_ble_ll_data.ll_rfclk_state != BLE_RFCLK_STATE_OFF) { ble_phy_rfclk_disable(); g_ble_ll_data.ll_rfclk_state = BLE_RFCLK_STATE_OFF; } } void ble_ll_xcvr_rfclk_stop(void) { os_cputime_timer_stop(&g_ble_ll_data.ll_rfclk_timer); ble_ll_xcvr_rfclk_disable(); } uint32_t ble_ll_xcvr_rfclk_time_till_settled(void) { int32_t dt; uint32_t rc; rc = 0; if (g_ble_ll_data.ll_rfclk_state == BLE_RFCLK_STATE_ON) { dt = (int32_t)(os_cputime_get32() - g_ble_ll_data.ll_rfclk_start_time); BLE_LL_ASSERT(dt >= 0); if (dt < g_ble_ll_data.ll_xtal_ticks) { rc = g_ble_ll_data.ll_xtal_ticks - (uint32_t)dt; } } return rc; } /** * Called when the timer to turn on the RF CLOCK expires. This function checks * the state of the clock. If the clock is off, the clock is turned on. * Otherwise, we just exit. * * Context: Interrupt * * @param arg */ void ble_ll_xcvr_rfclk_timer_exp(void *arg) { if (g_ble_ll_data.ll_rfclk_state == BLE_RFCLK_STATE_OFF) { ble_ll_xcvr_rfclk_start_now(os_cputime_get32()); } } /** * This API is used to turn on the rfclock without setting the cputime timer to * start the clock at some later point. * * NOTE: presumes that the state of the rf clock was checked prior to calling. * * @param now */ void ble_ll_xcvr_rfclk_start_now(uint32_t now) { ble_ll_xcvr_rfclk_enable(); g_ble_ll_data.ll_rfclk_start_time = now; } /** * Starts the timer that will turn the rf clock on. The 'cputime' is * the time at which the clock needs to be settled. * * @param cputime Time at which rfclock should be on and settled. */ void ble_ll_xcvr_rfclk_timer_start(uint32_t cputime) { /* * If we are currently in an advertising event or a connection event, * no need to start the cputime timer */ if ((g_ble_ll_data.ll_state == BLE_LL_STATE_ADV) || (g_ble_ll_data.ll_state == BLE_LL_STATE_CONNECTION)) { return; } /* Account for the settling time */ cputime -= g_ble_ll_data.ll_xtal_ticks; /* * If the timer is on the list, we need to see if its expiry is before * 'cputime'. If the expiry is before, no need to do anything. If it * is after, we need to stop the timer and start at new time. */ if (g_ble_ll_data.ll_rfclk_timer.link.tqe_prev != NULL) { if ((int32_t)(cputime - g_ble_ll_data.ll_rfclk_timer.expiry) >= 0) { return; } os_cputime_timer_stop(&g_ble_ll_data.ll_rfclk_timer); } os_cputime_timer_start(&g_ble_ll_data.ll_rfclk_timer, cputime); } #endif