blob: b7c48a3b3a651a9a080601d3ac7ac00c41300639 [file] [log] [blame]
/*
* 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 <stdint.h>
#include <stddef.h>
#include <assert.h>
#include <stddef.h>
#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)
{
g_ble_ll_data.ll_rfclk_state = BLE_RFCLK_STATE_ON;
ble_phy_rfclk_enable();
}
void
ble_ll_xcvr_rfclk_disable(void)
{
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