Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nrf53: Add APIs to change Low Frequency Clock source in the runtime #2993

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions hw/mcu/nordic/nrf5340/include/mcu/nrf5340_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ int nrf5340_clock_hfxo_request(void);
*/
int nrf5340_clock_hfxo_release(void);

/**
* Request low frequency clock source change.
*
* @param clksrc Value to determine requested clock source
* This parameter can be one of the following values:
* @arg CLOCK_LFCLKSTAT_SRC_LFRC - 32.768 kHz RC oscillator
* @arg CLOCK_LFCLKSTAT_SRC_LFXO - 32.768 kHz crystal oscillator
* @arg CLOCK_LFCLKSTAT_SRC_LFSYNT - 32.768 kHz synthesized from HFCLK
*
* @return int 0: clock source was already as requested. 1: clock source
* changed.
*/
int nrf5340_set_lf_clock_source(uint32_t clksrc);

/**
* Request HFCLK192M clock be turned on. Note that each request must have a
* corresponding release.
Expand Down
47 changes: 3 additions & 44 deletions hw/mcu/nordic/nrf5340/src/hal_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,6 @@ void
hal_system_clock_start(void)
{
#if MYNEWT_VAL(MCU_LFCLK_SOURCE)
uint32_t regmsk;
uint32_t regval;
uint32_t clksrc;

regmsk = CLOCK_LFCLKSTAT_STATE_Msk | CLOCK_LFCLKSTAT_SRC_Msk;
regval = CLOCK_LFCLKSTAT_STATE_Running << CLOCK_LFCLKSTAT_STATE_Pos;

#if MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFXO)

Expand All @@ -107,50 +101,15 @@ hal_system_clock_start(void)
NRF_P0->PIN_CNF[0] = GPIO_PIN_CNF_MCUSEL_Peripheral << GPIO_PIN_CNF_MCUSEL_Pos;
NRF_P0->PIN_CNF[1] = GPIO_PIN_CNF_MCUSEL_Peripheral << GPIO_PIN_CNF_MCUSEL_Pos;
#endif
regval |= CLOCK_LFCLKSTAT_SRC_LFXO << CLOCK_LFCLKSTAT_SRC_Pos;
clksrc = CLOCK_LFCLKSTAT_SRC_LFXO;
nrf5340_set_lf_clock_source(CLOCK_LFCLKSTAT_SRC_LFXO);
#elif MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFSYNTH)
regval |= CLOCK_LFCLKSTAT_SRC_LFSYNT << CLOCK_LFCLKSTAT_SRC_Pos;
clksrc = CLOCK_LFCLKSTAT_SRC_LFSYNT;
nrf5340_set_lf_clock_source(CLOCK_LFCLKSTAT_SRC_LFSYNT);
#elif MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFRC)
regval |= CLOCK_LFCLKSTAT_SRC_LFRC << CLOCK_LFCLKSTAT_SRC_Pos;
clksrc = CLOCK_LFCLKSTAT_SRC_LFRC;
nrf5340_set_lf_clock_source(CLOCK_LFCLKSTAT_SRC_LFRC);
#else
#error Unknown LFCLK source selected
#endif

#if MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFSYNTH)
/* Must turn on HFLCK for synthesized 32768 crystal */
if ((NRF_CLOCK->HFCLKSTAT & CLOCK_HFCLKSTAT_STATE_Msk) !=
(CLOCK_HFCLKSTAT_STATE_Running << CLOCK_HFCLKSTAT_STATE_Pos)) {
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
nrf5340_clock_hfxo_request();
while (1) {
if ((NRF_CLOCK->EVENTS_HFCLKSTARTED) != 0) {
break;
}
}
} else {
nrf5340_clock_hfxo_request();
}
#endif

/* Check if this clock source is already running */
if ((NRF_CLOCK->LFCLKSTAT & regmsk) != regval) {
NRF_CLOCK->TASKS_LFCLKSTOP = 1;
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK->LFCLKSRC = clksrc;
NRF_CLOCK->TASKS_LFCLKSTART = 1;

/* Wait here till started! */
while (1) {
if (NRF_CLOCK->EVENTS_LFCLKSTARTED) {
if ((NRF_CLOCK->LFCLKSTAT & regmsk) == regval) {
break;
}
}
}
}
#endif
if (MYNEWT_VAL(MCU_HFCLCK192_DIV) == 1) {
NRF_CLOCK->HFCLK192MCTRL = 0;
Expand Down
49 changes: 49 additions & 0 deletions hw/mcu/nordic/nrf5340/src/nrf5340_clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,52 @@ nrf5340_clock_hfclk192m_release(void)

return stopped;
}

int
nrf5340_set_lf_clock_source(uint32_t clksrc)
{
uint32_t regmsk;
uint32_t regval;

regmsk = CLOCK_LFCLKSTAT_STATE_Msk | CLOCK_LFCLKSTAT_SRC_Msk;
regval = CLOCK_LFCLKSTAT_STATE_Running << CLOCK_LFCLKSTAT_STATE_Pos;

regval |= clksrc << CLOCK_LFCLKSTAT_SRC_Pos;

/* Check if this clock source isn't already running */
if ((NRF_CLOCK->LFCLKSTAT & regmsk) == regval) {
return 0;
}

/*
* Request HFXO if LFSYNTH is going to be set as source. If LFSYNTH is going to be
* replaced with other source, release HFXO.
*/
if (clksrc == CLOCK_LFCLKSTAT_SRC_LFSYNT) {
if ((NRF_CLOCK->HFCLKSTAT & CLOCK_HFCLKSTAT_STATE_Msk) !=
(CLOCK_HFCLKSTAT_STATE_Running << CLOCK_HFCLKSTAT_STATE_Pos)) {
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
nrf5340_clock_hfxo_request();
while (!NRF_CLOCK->EVENTS_HFCLKSTARTED) {
}
} else {
nrf5340_clock_hfxo_request();
}
} else if (NRF_CLOCK->LFCLKSRC == CLOCK_LFCLKSTAT_SRC_LFSYNT) {
nrf5340_clock_hfxo_release();
}

NRF_CLOCK->LFCLKSRC = clksrc;
NRF_CLOCK->TASKS_LFCLKSTART = 1;

/* Wait here till started! */
while (1) {
if (NRF_CLOCK->EVENTS_LFCLKSTARTED) {
if ((NRF_CLOCK->LFCLKSTAT & regmsk) == regval) {
break;
}
}
}

return 1;
}
14 changes: 14 additions & 0 deletions hw/mcu/nordic/nrf5340_net/include/mcu/nrf5340_net_clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,20 @@ int nrf5340_net_clock_hfxo_request(void);
*/
int nrf5340_net_clock_hfxo_release(void);

/**
* Request low frequency clock source change.
*
* @param clksrc Value to determine requested clock source
* This parameter can be one of the following values:
* @arg CLOCK_LFCLKSTAT_SRC_LFRC - 32.768 kHz RC oscillator
* @arg CLOCK_LFCLKSTAT_SRC_LFXO - 32.768 kHz crystal oscillator
* @arg CLOCK_LFCLKSTAT_SRC_LFSYNT - 32.768 kHz synthesized from HFCLK
*
* @return int 0: clock source was already as requested. 1: clock source
* changed.
*/
int nrf5340_net_set_lf_clock_source(uint32_t clksrc);

#ifdef __cplusplus
}
#endif
Expand Down
47 changes: 3 additions & 44 deletions hw/mcu/nordic/nrf5340_net/src/hal_system.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,57 +70,16 @@ void
hal_system_clock_start(void)
{
#if MYNEWT_VAL(MCU_LFCLK_SOURCE)
uint32_t regmsk;
uint32_t regval;
uint32_t clksrc;

regmsk = CLOCK_LFCLKSTAT_STATE_Msk | CLOCK_LFCLKSTAT_SRC_Msk;
regval = CLOCK_LFCLKSTAT_STATE_Running << CLOCK_LFCLKSTAT_STATE_Pos;

#if MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFXO)
regval |= CLOCK_LFCLKSTAT_SRC_LFXO << CLOCK_LFCLKSTAT_SRC_Pos;
clksrc = CLOCK_LFCLKSTAT_SRC_LFXO;
nrf5340_net_set_lf_clock_source(CLOCK_LFCLKSTAT_SRC_LFXO);
#elif MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFSYNTH)
regval |= CLOCK_LFCLKSTAT_SRC_LFSYNT << CLOCK_LFCLKSTAT_SRC_Pos;
clksrc = CLOCK_LFCLKSTAT_SRC_LFSYNT;
nrf5340_net_set_lf_clock_source(CLOCK_LFCLKSTAT_SRC_LFSYNT);
#elif MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFRC)
regval |= CLOCK_LFCLKSTAT_SRC_LFRC << CLOCK_LFCLKSTAT_SRC_Pos;
clksrc = CLOCK_LFCLKSTAT_SRC_LFRC;
nrf5340_net_set_lf_clock_source(CLOCK_LFCLKSTAT_SRC_LFRC);
#else
#error Unknown LFCLK source selected
#endif

#if MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFSYNTH)
/* Must turn on HFLCK for synthesized 32768 crystal */
if ((NRF_CLOCK_NS->HFCLKSTAT & CLOCK_HFCLKSTAT_STATE_Msk) !=
(CLOCK_HFCLKSTAT_STATE_Running << CLOCK_HFCLKSTAT_STATE_Pos)) {
NRF_CLOCK_NS->EVENTS_HFCLKSTARTED = 0;
nrf5340_net_clock_hfxo_request();
while (1) {
if ((NRF_CLOCK_NS->EVENTS_HFCLKSTARTED) != 0) {
break;
}
}
} else {
nrf5340_net_clock_hfxo_request();
}
#endif

/* Check if this clock source is already running */
if ((NRF_CLOCK_NS->LFCLKSTAT & regmsk) != regval) {
NRF_CLOCK_NS->TASKS_LFCLKSTOP = 1;
NRF_CLOCK_NS->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK_NS->LFCLKSRC = clksrc;
NRF_CLOCK_NS->TASKS_LFCLKSTART = 1;

/* Wait here till started! */
while (1) {
if (NRF_CLOCK_NS->EVENTS_LFCLKSTARTED) {
if ((NRF_CLOCK_NS->LFCLKSTAT & regmsk) == regval) {
break;
}
}
}
}
#endif
}
55 changes: 55 additions & 0 deletions hw/mcu/nordic/nrf5340_net/src/nrf5340_net_clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,58 @@ nrf5340_net_clock_hfxo_release(void)

return stopped;
}

/**
* Request low frequency clock source change.
*
* @return int 0: clock source was already as requested. 1: clock source
* changed.
*/
int
nrf5340_net_set_lf_clock_source(uint32_t clksrc)
{
uint32_t regmsk;
uint32_t regval;

regmsk = CLOCK_LFCLKSTAT_STATE_Msk | CLOCK_LFCLKSTAT_SRC_Msk;
regval = CLOCK_LFCLKSTAT_STATE_Running << CLOCK_LFCLKSTAT_STATE_Pos;

regval |= clksrc << CLOCK_LFCLKSTAT_SRC_Pos;

/* Check if this clock source isn't already running */
if ((NRF_CLOCK_NS->LFCLKSTAT & regmsk) == regval) {
return 0;
}

/*
* Request HFXO if LFSYNTH is going to be set as source. If LFSYNTH is going to be
* replaced with other source, release HFXO.
*/
if (clksrc == CLOCK_LFCLKSTAT_SRC_LFSYNT) {
if ((NRF_CLOCK_NS->HFCLKSTAT & CLOCK_HFCLKSTAT_STATE_Msk) !=
(CLOCK_HFCLKSTAT_STATE_Running << CLOCK_HFCLKSTAT_STATE_Pos)) {
NRF_CLOCK_NS->EVENTS_HFCLKSTARTED = 0;
nrf5340_net_clock_hfxo_request();
while (!NRF_CLOCK_NS->EVENTS_HFCLKSTARTED) {
}
} else {
nrf5340_net_clock_hfxo_request();
}
} else if (NRF_CLOCK_NS->LFCLKSRC == CLOCK_LFCLKSTAT_SRC_LFSYNT) {
nrf5340_net_clock_hfxo_release();
}

NRF_CLOCK_NS->LFCLKSRC = clksrc;
NRF_CLOCK_NS->TASKS_LFCLKSTART = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lfclk source can be changes without restarting lfclk:
The LFCLK source can be configured at any time (for instance, when the LFCLK has already been started). The content of the LFCLKSRC register only takes effect when the LFCLKSTART task is triggered.

so we can only start lfclk once on system startup, then this API can change source at any time only taking care of hfxo when switching to/from lfsynth


/* Wait here till started! */
while (1) {
if (NRF_CLOCK_NS->EVENTS_LFCLKSTARTED) {
if ((NRF_CLOCK_NS->LFCLKSTAT & regmsk) == regval) {
break;
}
}
}

return 1;
}