bluetooth: controller: openisa/RV32M1: introducing radio Deep Sleep Mode

Added the functions to turn on/off the radio.
Deep Sleep Mode (DSM)

Signed-off-by: Ionut Ursescu <ionut.ursescu@nxp.com>
Signed-off-by: George Stefan <george.stefan@nxp.com>
This commit is contained in:
Ionut Ursescu 2019-12-16 15:47:52 +02:00 committed by Johan Hedberg
commit 27878377b2
2 changed files with 108 additions and 1 deletions

View file

@ -11,6 +11,7 @@
#include <sys/mempool_base.h>
#include <toolchain.h>
#include <irq.h>
#include <errno.h>
#include "util/mem.h"
#include "hal/ccm.h"
@ -54,9 +55,21 @@ static void *isr_cb_param;
* buffer
*/
#define RADIO_ACTIVE_MASK 0x1fff
#define RADIO_DISABLE_TMR 4 /* us */
/* Delay needed in order to exit and enter Manual DSM.
* Should happen after radio_tmr_start() */
#define DSM_ENTER_DELAY_TICKS 8
/* Mask to determine the state of DSM machine */
#define MAN_DSM_ON (RSIM_DSM_CONTROL_MAN_DEEP_SLEEP_STATUS_MASK \
| RSIM_DSM_CONTROL_DSM_MAN_READY_MASK \
| RSIM_DSM_CONTROL_MAN_SLEEP_REQUEST_MASK) \
static u32_t dsm_ref; /* DSM reference counter */
static u32_t rtc_start;
static u32_t rtc_diff_start_us;
@ -389,7 +402,10 @@ void radio_setup(void)
hpmcal_disable();
#endif
/* enable the CRC as it is disabled by default after reset */
/* Enable Deep Sleep Mode for GENFSK */
XCVR_MISC->XCVR_CTRL |= XCVR_CTRL_XCVR_CTRL_MAN_DSM_SEL(2);
/* Enable the CRC as it is disabled by default after reset */
XCVR_MISC->CRCW_CFG |= XCVR_CTRL_CRCW_CFG_CRCW_EN(1);
/* Assign Radio #0 Interrupt to GENERIC_FSK */
@ -424,6 +440,14 @@ void radio_setup(void)
GENFSK->WHITEN_SZ_THR |= GENFSK_WHITEN_SZ_THR_REC_BAD_PKT(1);
get_isr_latency();
/* Turn radio off */
if (is_radio_off()) {
dsm_ref = 0;
} else {
dsm_ref = 1;
radio_sleep();
}
}
void radio_reset(void)
@ -1340,3 +1364,82 @@ u32_t radio_ar_has_match(void)
/* printk("%s\n", __func__); */
return 0;
}
u32_t radio_sleep(void)
{
if (dsm_ref == 0) {
return -EALREADY;
}
u32_t localref = --dsm_ref;
/* These opertions (decrement, check) should be atomic/critical section
* since we turn radio on/off from different contexts/ISRs (LLL, radio).
* It's fine for now as all the contexts have the same priority and
* don't preempt each other. */
if (localref == 0) {
u32_t status = (RSIM->DSM_CONTROL & MAN_DSM_ON);
if (status) {
/* Allready in sleep mode */
return 0;
}
/* Disable timer */
RSIM->DSM_CONTROL &= ~RSIM_DSM_CONTROL_DSM_TIMER_EN(1);
/* Get current DSM_TIMER value */
u32_t dsm_timer = RSIM->DSM_TIMER;
/* Set Sleep time after DSM_ENTER_DELAY */
RSIM->MAN_SLEEP = RSIM_MAN_SLEEP_MAN_SLEEP_TIME(dsm_timer +
DSM_ENTER_DELAY_TICKS);
/* Set Wake time to max, we use DSM early exit */
RSIM->MAN_WAKE = RSIM_MAN_WAKE_MAN_WAKE_TIME(dsm_timer - 1);
/* MAN wakeup request enable */
RSIM->DSM_CONTROL |= RSIM_DSM_CONTROL_MAN_WAKEUP_REQUEST_EN(1);
/* Enable DSM, sending a sleep request */
GENFSK->DSM_CTRL |= GENFSK_DSM_CTRL_GEN_SLEEP_REQUEST(1);
/* Enable timer */
RSIM->DSM_CONTROL |= RSIM_DSM_CONTROL_DSM_TIMER_EN(1);
}
return 0;
}
u32_t radio_wake(void)
{
u32_t localref = ++dsm_ref;
/* These opertions (increment, check) should be atomic/critical section
* since we turn radio on/off from different contexts/ISRs (LLL, radio).
* It's fine for now as all the contexts have the same priority and
* don't preempt each other. */
if (localref == 1) {
u32_t status = (RSIM->DSM_CONTROL & MAN_DSM_ON);
if (!status) {
/* Not in sleep mode */
return 0;
}
/* Get current DSM_TIMER value */
u32_t dsm_timer = RSIM->DSM_TIMER;
/* Set Wake time after DSM_ENTER_DELAY */
RSIM->MAN_WAKE = RSIM_MAN_WAKE_MAN_WAKE_TIME(dsm_timer +
DSM_ENTER_DELAY_TICKS);
}
return 0;
}
u32_t is_radio_off(void)
{
u32_t status = (RSIM->DSM_CONTROL & MAN_DSM_ON);
return status;
}

View file

@ -102,3 +102,7 @@ void radio_ar_configure(u32_t nirk, void *irk);
u32_t radio_ar_match_get(void);
void radio_ar_status_reset(void);
u32_t radio_ar_has_match(void);
u32_t radio_sleep(void);
u32_t radio_wake(void);
u32_t is_radio_off(void);