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