Skip to content

Commit

Permalink
[nrf fromtree] drivers: clock_control: nrf: hfxo: impl zero-latency i…
Browse files Browse the repository at this point in the history
…sr API

Implement the zero latency interrupt safe APIs to the HFXO clock
commonly used by the bluetooth stach from zero latency interrupt
context.

Co-authored-by: Piotr Pryga <[email protected]>

Signed-off-by: Bjarki Arge Andreasen <[email protected]>
Signed-off-by: Piotr Pryga <[email protected]>
(cherry picked from commit 73a45a7)
Signed-off-by: Piotr Pryga <[email protected]>
  • Loading branch information
bjarki-andreasen authored and jukkar committed Dec 19, 2024
1 parent bd64dc9 commit 6e09b7a
Showing 1 changed file with 105 additions and 6 deletions.
111 changes: 105 additions & 6 deletions drivers/clock_control/clock_control_nrf2_hfxo.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ struct dev_data_hfxo {
onoff_notify_fn notify;
struct k_timer timer;
sys_snode_t hfxo_node;
#if defined(CONFIG_ZERO_LATENCY_IRQS)
uint16_t request_count;
#endif /* CONFIG_ZERO_LATENCY_IRQS */
};

struct dev_config_hfxo {
Expand All @@ -29,6 +32,31 @@ struct dev_config_hfxo {
k_timeout_t start_up_time;
};

#if defined(CONFIG_ZERO_LATENCY_IRQS)
static uint32_t full_irq_lock(void)
{
uint32_t mcu_critical_state;

if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) {
mcu_critical_state = __get_PRIMASK();
__disable_irq();
} else {
mcu_critical_state = irq_lock();
}

return mcu_critical_state;
}

static void full_irq_unlock(uint32_t mcu_critical_state)
{
if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) {
__set_PRIMASK(mcu_critical_state);
} else {
irq_unlock(mcu_critical_state);
}
}
#endif /* CONFIG_ZERO_LATENCY_IRQS */

static void hfxo_start_up_timer_handler(struct k_timer *timer)
{
struct dev_data_hfxo *dev_data =
Expand All @@ -48,6 +76,40 @@ static void hfxo_start_up_timer_handler(struct k_timer *timer)
}
}

static void start_hfxo(struct dev_data_hfxo *dev_data)
{
nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED);
soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO);
}

static void request_hfxo(struct dev_data_hfxo *dev_data)
{
#if defined(CONFIG_ZERO_LATENCY_IRQS)
unsigned int key;

key = full_irq_lock();
if (dev_data->request_count == 0) {
start_hfxo(dev_data);
}

dev_data->request_count++;
full_irq_unlock(key);
#else
start_hfxo(dev_data);
#endif /* CONFIG_ZERO_LATENCY_IRQS */
}

#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
void nrf_clock_control_hfxo_request(void)
{
const struct device *dev = DEVICE_DT_INST_GET(0);
struct dev_data_hfxo *dev_data = dev->data;

request_hfxo(dev_data);
}
#endif /* CONFIG_ZERO_LATENCY_IRQS */

static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
{
struct dev_data_hfxo *dev_data =
Expand All @@ -56,10 +118,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
const struct dev_config_hfxo *dev_config = dev->config;

dev_data->notify = notify;

nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED);
soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO);
request_hfxo(dev_data);

/* Due to a hardware issue, the HFXOSTARTED event is currently
* unreliable. Hence the timer is used to simply wait the expected
Expand All @@ -68,13 +127,53 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
k_timer_start(&dev_data->timer, dev_config->start_up_time, K_NO_WAIT);
}

static void stop_hfxo(struct dev_data_hfxo *dev_data)
{
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO);
soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
}

static void release_hfxo(struct dev_data_hfxo *dev_data)
{
#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
unsigned int key;

key = full_irq_lock();
if (dev_data->request_count < 1) {
full_irq_unlock(key);
/* Misuse of the API, release without request? */
__ASSERT_NO_MSG(false);
/* In case asserts are disabled early return due to no requests pending */
return;
}

dev_data->request_count--;
if (dev_data->request_count < 1) {
stop_hfxo(dev_data);
}

full_irq_unlock(key);
#else
stop_hfxo(dev_data);
#endif /* CONFIG_ZERO_LATENCY_IRQS */
}

#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
void nrf_clock_control_hfxo_release(void)
{
const struct device *dev = DEVICE_DT_INST_GET(0);
struct dev_data_hfxo *dev_data = dev->data;

release_hfxo(dev_data);
}
#endif /* IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) */

static void onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
{
struct dev_data_hfxo *dev_data =
CONTAINER_OF(mgr, struct dev_data_hfxo, mgr);

nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO);
soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
release_hfxo(dev_data);
notify(mgr, 0);
}

Expand Down

0 comments on commit 6e09b7a

Please sign in to comment.