Skip to content

Commit ee72f48

Browse files
bjarki-andreasenppryga-nordic
authored andcommitted
[nrf fromtree] drivers: clock_control: nrf: hfxo: impl zero-latency isr 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]>
1 parent d0fc307 commit ee72f48

File tree

1 file changed

+105
-6
lines changed

1 file changed

+105
-6
lines changed

drivers/clock_control/clock_control_nrf2_hfxo.c

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ struct dev_data_hfxo {
2121
onoff_notify_fn notify;
2222
struct k_timer timer;
2323
sys_snode_t hfxo_node;
24+
#if defined(CONFIG_ZERO_LATENCY_IRQS)
25+
uint16_t request_count;
26+
#endif /* CONFIG_ZERO_LATENCY_IRQS */
2427
};
2528

2629
struct dev_config_hfxo {
@@ -29,6 +32,31 @@ struct dev_config_hfxo {
2932
k_timeout_t start_up_time;
3033
};
3134

35+
#if defined(CONFIG_ZERO_LATENCY_IRQS)
36+
static uint32_t full_irq_lock(void)
37+
{
38+
uint32_t mcu_critical_state;
39+
40+
if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) {
41+
mcu_critical_state = __get_PRIMASK();
42+
__disable_irq();
43+
} else {
44+
mcu_critical_state = irq_lock();
45+
}
46+
47+
return mcu_critical_state;
48+
}
49+
50+
static void full_irq_unlock(uint32_t mcu_critical_state)
51+
{
52+
if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) {
53+
__set_PRIMASK(mcu_critical_state);
54+
} else {
55+
irq_unlock(mcu_critical_state);
56+
}
57+
}
58+
#endif /* CONFIG_ZERO_LATENCY_IRQS */
59+
3260
static void hfxo_start_up_timer_handler(struct k_timer *timer)
3361
{
3462
struct dev_data_hfxo *dev_data =
@@ -48,6 +76,40 @@ static void hfxo_start_up_timer_handler(struct k_timer *timer)
4876
}
4977
}
5078

79+
static void start_hfxo(struct dev_data_hfxo *dev_data)
80+
{
81+
nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED);
82+
soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
83+
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO);
84+
}
85+
86+
static void request_hfxo(struct dev_data_hfxo *dev_data)
87+
{
88+
#if defined(CONFIG_ZERO_LATENCY_IRQS)
89+
unsigned int key;
90+
91+
key = full_irq_lock();
92+
if (dev_data->request_count == 0) {
93+
start_hfxo(dev_data);
94+
}
95+
96+
dev_data->request_count++;
97+
full_irq_unlock(key);
98+
#else
99+
start_hfxo(dev_data);
100+
#endif /* CONFIG_ZERO_LATENCY_IRQS */
101+
}
102+
103+
#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
104+
void nrf_clock_control_hfxo_request(void)
105+
{
106+
const struct device *dev = DEVICE_DT_INST_GET(0);
107+
struct dev_data_hfxo *dev_data = dev->data;
108+
109+
request_hfxo(dev_data);
110+
}
111+
#endif /* CONFIG_ZERO_LATENCY_IRQS */
112+
51113
static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
52114
{
53115
struct dev_data_hfxo *dev_data =
@@ -56,10 +118,7 @@ static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
56118
const struct dev_config_hfxo *dev_config = dev->config;
57119

58120
dev_data->notify = notify;
59-
60-
nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED);
61-
soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
62-
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO);
121+
request_hfxo(dev_data);
63122

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

130+
static void stop_hfxo(struct dev_data_hfxo *dev_data)
131+
{
132+
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO);
133+
soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
134+
}
135+
136+
static void release_hfxo(struct dev_data_hfxo *dev_data)
137+
{
138+
#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
139+
unsigned int key;
140+
141+
key = full_irq_lock();
142+
if (dev_data->request_count < 1) {
143+
full_irq_unlock(key);
144+
/* Misuse of the API, release without request? */
145+
__ASSERT_NO_MSG(false);
146+
/* In case asserts are disabled early return due to no requests pending */
147+
return;
148+
}
149+
150+
dev_data->request_count--;
151+
if (dev_data->request_count < 1) {
152+
stop_hfxo(dev_data);
153+
}
154+
155+
full_irq_unlock(key);
156+
#else
157+
stop_hfxo(dev_data);
158+
#endif /* CONFIG_ZERO_LATENCY_IRQS */
159+
}
160+
161+
#if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
162+
void nrf_clock_control_hfxo_release(void)
163+
{
164+
const struct device *dev = DEVICE_DT_INST_GET(0);
165+
struct dev_data_hfxo *dev_data = dev->data;
166+
167+
release_hfxo(dev_data);
168+
}
169+
#endif /* IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) */
170+
71171
static void onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
72172
{
73173
struct dev_data_hfxo *dev_data =
74174
CONTAINER_OF(mgr, struct dev_data_hfxo, mgr);
75175

76-
nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO);
77-
soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
176+
release_hfxo(dev_data);
78177
notify(mgr, 0);
79178
}
80179

0 commit comments

Comments
 (0)