1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT nordic_nrf_bellboard_rx
7
8 #include <zephyr/devicetree.h>
9 #include <zephyr/drivers/mbox.h>
10 #include <zephyr/sys/util.h>
11 #include <zephyr/sys/__assert.h>
12
13 #include <hal/nrf_bellboard.h>
14
15 #define BELLBOARD_NUM_IRQS 4U
16
17 BUILD_ASSERT(DT_NUM_IRQS(DT_DRV_INST(0)) <= BELLBOARD_NUM_IRQS, "# interrupt exceeds maximum");
18
19 BUILD_ASSERT((DT_INST_PROP_LEN(0, nordic_interrupt_mapping) % 2) == 0,
20 "# interrupt mappings not specified in pairs");
21
22 /* BELLBOARD event mappings */
23 #define EVT_MAPPING_ITEM(idx) DT_INST_PROP_BY_IDX(0, nordic_interrupt_mapping, idx)
24 #define BELLBOARD_GET_EVT_MAPPING(idx, _) \
25 COND_CODE_1( \
26 DT_INST_PROP_HAS_IDX(0, nordic_interrupt_mapping, UTIL_INC(UTIL_X2(idx))), \
27 ([EVT_MAPPING_ITEM(UTIL_INC(UTIL_X2(idx)))] = EVT_MAPPING_ITEM(UTIL_X2(idx)),), \
28 ())
29
30 static const uint32_t evt_mappings[BELLBOARD_NUM_IRQS] = {
31 LISTIFY(DT_NUM_IRQS(DT_DRV_INST(0)), BELLBOARD_GET_EVT_MAPPING, ())};
32
33 /* BELLBOARD instance */
34 static NRF_BELLBOARD_Type *bellboard = (NRF_BELLBOARD_Type *)DT_INST_REG_ADDR(0);
35
36 /* BELLBOARD runtime resources */
37 static mbox_callback_t cbs[NRF_BELLBOARD_EVENTS_TRIGGERED_COUNT];
38 static void *cbs_ctx[NRF_BELLBOARD_EVENTS_TRIGGERED_COUNT];
39 static uint32_t evt_enabled_masks[BELLBOARD_NUM_IRQS];
40
bellboard_rx_isr(const void * parameter)41 static void bellboard_rx_isr(const void *parameter)
42 {
43 uint8_t irq_idx = (uint8_t)(uintptr_t)parameter;
44 uint32_t int_pend;
45
46 int_pend = nrf_bellboard_int_pending_get(bellboard, irq_idx);
47
48 for (uint8_t i = 0U; i < NRF_BELLBOARD_EVENTS_TRIGGERED_COUNT; i++) {
49 nrf_bellboard_event_t event = nrf_bellboard_triggered_event_get(i);
50
51 if ((int_pend & BIT(i)) != 0U) {
52 /* Only clear those events that have their corresponding bit set
53 * in INTPEND at the time we read it. Otherwise, if two (or more)
54 * events are generated in quick succession, INTPEND may be set for
55 * only one of events, but we clear the EVENTS_TRIGGERED bit for
56 * all of them, thus losing them.
57 *
58 * Assume nrf_bellboard_event_check() is true for the event
59 * that raised this interrupt.
60 */
61 __ASSERT_NO_MSG(nrf_bellboard_event_check(bellboard, event));
62
63 nrf_bellboard_event_clear(bellboard, event);
64
65 if (cbs[i] != NULL) {
66 cbs[i](DEVICE_DT_INST_GET(0), i, cbs_ctx[i], NULL);
67 }
68 }
69 }
70 }
71
bellboard_rx_max_channels_get(const struct device * dev)72 static uint32_t bellboard_rx_max_channels_get(const struct device *dev)
73 {
74 ARG_UNUSED(dev);
75
76 return NRF_BELLBOARD_EVENTS_TRIGGERED_COUNT;
77 }
78
bellboard_rx_register_callback(const struct device * dev,uint32_t id,mbox_callback_t cb,void * user_data)79 static int bellboard_rx_register_callback(const struct device *dev, uint32_t id, mbox_callback_t cb,
80 void *user_data)
81 {
82 ARG_UNUSED(dev);
83
84 if (id >= NRF_BELLBOARD_EVENTS_TRIGGERED_COUNT) {
85 return -EINVAL;
86 }
87
88 cbs[id] = cb;
89 cbs_ctx[id] = user_data;
90
91 return 0;
92 }
93
bellboard_rx_set_enabled(const struct device * dev,uint32_t id,bool enable)94 static int bellboard_rx_set_enabled(const struct device *dev, uint32_t id, bool enable)
95 {
96 bool valid_found = false;
97
98 ARG_UNUSED(dev);
99
100 if (id >= NRF_BELLBOARD_EVENTS_TRIGGERED_COUNT) {
101 return -EINVAL;
102 }
103
104 for (uint8_t i = 0U; i < BELLBOARD_NUM_IRQS; i++) {
105 uint32_t *evt_enabled_mask;
106
107 if ((evt_mappings[i] == 0U) || ((evt_mappings[i] & BIT(id)) == 0U)) {
108 continue;
109 }
110
111 valid_found = true;
112 evt_enabled_mask = &evt_enabled_masks[i];
113
114 if (enable) {
115 if ((*evt_enabled_mask & BIT(id)) != 0U) {
116 return -EALREADY;
117 }
118
119 *evt_enabled_mask |= BIT(id);
120 nrf_bellboard_int_enable(bellboard, i, BIT(id));
121 } else {
122 if ((*evt_enabled_mask & BIT(id)) == 0U) {
123 return -EALREADY;
124 }
125
126 *evt_enabled_mask &= ~BIT(id);
127 nrf_bellboard_int_disable(bellboard, i, BIT(id));
128 }
129 }
130
131 if (!valid_found) {
132 return -EINVAL;
133 }
134
135 return 0;
136 }
137
138 static const struct mbox_driver_api bellboard_rx_driver_api = {
139 .max_channels_get = bellboard_rx_max_channels_get,
140 .register_callback = bellboard_rx_register_callback,
141 .set_enabled = bellboard_rx_set_enabled,
142 };
143
144 #define BELLBOARD_IRQ_CONFIGURE(name, idx) \
145 COND_CODE_1(DT_INST_IRQ_HAS_NAME(0, name), \
146 (IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, name, irq), \
147 DT_INST_IRQ_BY_NAME(0, name, priority), bellboard_rx_isr, \
148 (const void *)idx, 0); \
149 irq_enable(DT_INST_IRQ_BY_NAME(0, name, irq));), \
150 ())
151
bellboard_rx_init(const struct device * dev)152 static int bellboard_rx_init(const struct device *dev)
153 {
154 uint32_t evt_all_mappings =
155 evt_mappings[0] | evt_mappings[1] | evt_mappings[2] | evt_mappings[3];
156
157 ARG_UNUSED(dev);
158
159 nrf_bellboard_int_disable(bellboard, 0, evt_mappings[0]);
160 nrf_bellboard_int_disable(bellboard, 1, evt_mappings[1]);
161 nrf_bellboard_int_disable(bellboard, 2, evt_mappings[2]);
162 nrf_bellboard_int_disable(bellboard, 3, evt_mappings[3]);
163
164 for (uint8_t i = 0U; i < NRF_BELLBOARD_EVENTS_TRIGGERED_COUNT; i++) {
165 if ((evt_all_mappings & BIT(i)) != 0U) {
166 nrf_bellboard_event_clear(bellboard, nrf_bellboard_triggered_event_get(i));
167 }
168 }
169
170 BELLBOARD_IRQ_CONFIGURE(irq0, 0);
171 BELLBOARD_IRQ_CONFIGURE(irq1, 1);
172 BELLBOARD_IRQ_CONFIGURE(irq2, 2);
173 BELLBOARD_IRQ_CONFIGURE(irq3, 3);
174
175 return 0;
176 }
177
178 DEVICE_DT_INST_DEFINE(0, bellboard_rx_init, NULL, NULL, NULL, POST_KERNEL,
179 CONFIG_MBOX_INIT_PRIORITY, &bellboard_rx_driver_api);
180