1 /*
2  * Copyright 2023-2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_s32_wkpu
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/irq.h>
12 #include <zephyr/sys/sys_io.h>
13 #include <zephyr/sys/math_extras.h>
14 #include <zephyr/drivers/interrupt_controller/intc_wkpu_nxp_s32.h>
15 
16 /* NMI Status Flag Register */
17 #define WKPU_NSR       0x0
18 /* NMI Configuration Register */
19 #define WKPU_NCR       0x8
20 /* Wakeup/Interrupt Status Flag Register */
21 #define WKPU_WISR(n)   (0x14 + 0x40 * (n))
22 /* Interrupt Request Enable Register */
23 #define WKPU_IRER(n)   (0x18 + 0x40 * (n))
24 /* Wakeup Request Enable Register */
25 #define WKPU_WRER(n)   (0x1c + 0x40 * (n))
26 /* Wakeup/Interrupt Rising-Edge Event Enable Register */
27 #define WKPU_WIREER(n) (0x28 + 0x40 * (n))
28 /* Wakeup/Interrupt Falling-Edge Event Enable Register */
29 #define WKPU_WIFEER(n) (0x2c + 0x40 * (n))
30 /* Wakeup/Interrupt Filter Enable Register */
31 #define WKPU_WIFER(n)  (0x30 + 0x40 * (n))
32 
33 /* Handy accessors */
34 #define REG_READ(r)     sys_read32(config->base + (r))
35 #define REG_WRITE(r, v) sys_write32((v), config->base + (r))
36 
37 struct wkpu_nxp_s32_config {
38 	mem_addr_t base;
39 	uint64_t filter_enable;
40 };
41 
42 struct wkpu_nxp_s32_cb {
43 	wkpu_nxp_s32_callback_t cb;
44 	uint8_t pin;
45 	void *data;
46 };
47 
48 struct wkpu_nxp_s32_data {
49 	struct wkpu_nxp_s32_cb *cb;
50 };
51 
wkpu_nxp_s32_interrupt_handler(const struct device * dev)52 static void wkpu_nxp_s32_interrupt_handler(const struct device *dev)
53 {
54 	const struct wkpu_nxp_s32_config *config = dev->config;
55 	struct wkpu_nxp_s32_data *data = dev->data;
56 	uint64_t pending = wkpu_nxp_s32_get_pending(dev);
57 	uint64_t irq_mask;
58 	int irq;
59 
60 	while (pending) {
61 		irq_mask = LSB_GET(pending);
62 		irq = u64_count_trailing_zeros(irq_mask);
63 
64 		/* Clear status flag */
65 		REG_WRITE(WKPU_WISR(irq / 32U), REG_READ(WKPU_WISR(irq / 32U)) | irq_mask);
66 
67 		if (data->cb[irq].cb != NULL) {
68 			data->cb[irq].cb(data->cb[irq].pin, data->cb[irq].data);
69 		}
70 
71 		pending ^= irq_mask;
72 	}
73 }
74 
wkpu_nxp_s32_set_callback(const struct device * dev,uint8_t irq,uint8_t pin,wkpu_nxp_s32_callback_t cb,void * arg)75 int wkpu_nxp_s32_set_callback(const struct device *dev, uint8_t irq, uint8_t pin,
76 			      wkpu_nxp_s32_callback_t cb, void *arg)
77 {
78 	struct wkpu_nxp_s32_data *data = dev->data;
79 
80 	__ASSERT_NO_MSG(irq < CONFIG_NXP_S32_WKPU_SOURCES_MAX);
81 
82 	if ((data->cb[irq].cb == cb) && (data->cb[irq].data == arg)) {
83 		return 0;
84 	}
85 
86 	if (data->cb[irq].cb) {
87 		return -EBUSY;
88 	}
89 
90 	data->cb[irq].cb = cb;
91 	data->cb[irq].pin = pin;
92 	data->cb[irq].data = arg;
93 
94 	return 0;
95 }
96 
wkpu_nxp_s32_unset_callback(const struct device * dev,uint8_t irq)97 void wkpu_nxp_s32_unset_callback(const struct device *dev, uint8_t irq)
98 {
99 	struct wkpu_nxp_s32_data *data = dev->data;
100 
101 	__ASSERT_NO_MSG(irq < CONFIG_NXP_S32_WKPU_SOURCES_MAX);
102 
103 	data->cb[irq].cb = NULL;
104 	data->cb[irq].pin = 0;
105 	data->cb[irq].data = NULL;
106 }
107 
wkpu_nxp_s32_enable_interrupt(const struct device * dev,uint8_t irq,enum wkpu_nxp_s32_trigger trigger)108 void wkpu_nxp_s32_enable_interrupt(const struct device *dev, uint8_t irq,
109 				   enum wkpu_nxp_s32_trigger trigger)
110 {
111 	const struct wkpu_nxp_s32_config *config = dev->config;
112 	uint32_t mask = BIT(irq % 32U);
113 	uint8_t reg_idx = irq / 32U;
114 	uint32_t reg_val;
115 
116 	__ASSERT_NO_MSG(irq < CONFIG_NXP_S32_WKPU_SOURCES_MAX);
117 
118 	/* Configure trigger */
119 	reg_val = REG_READ(WKPU_WIREER(reg_idx));
120 	if ((trigger == WKPU_NXP_S32_RISING_EDGE) || (trigger == WKPU_NXP_S32_BOTH_EDGES)) {
121 		reg_val |= mask;
122 	} else {
123 		reg_val &= ~mask;
124 	}
125 	REG_WRITE(WKPU_WIREER(reg_idx), reg_val);
126 
127 	reg_val = REG_READ(WKPU_WIFEER(reg_idx));
128 	if ((trigger == WKPU_NXP_S32_FALLING_EDGE) || (trigger == WKPU_NXP_S32_BOTH_EDGES)) {
129 		reg_val |= mask;
130 	} else {
131 		reg_val &= ~mask;
132 	}
133 	REG_WRITE(WKPU_WIFEER(reg_idx), reg_val);
134 
135 	/* Clear status flag and unmask interrupt */
136 	REG_WRITE(WKPU_WISR(reg_idx), REG_READ(WKPU_WISR(reg_idx)) | mask);
137 	REG_WRITE(WKPU_IRER(reg_idx), REG_READ(WKPU_IRER(reg_idx)) | mask);
138 }
139 
wkpu_nxp_s32_disable_interrupt(const struct device * dev,uint8_t irq)140 void wkpu_nxp_s32_disable_interrupt(const struct device *dev, uint8_t irq)
141 {
142 	const struct wkpu_nxp_s32_config *config = dev->config;
143 	uint32_t mask = BIT(irq % 32U);
144 	uint8_t reg_idx = irq / 32U;
145 
146 	__ASSERT_NO_MSG(irq < CONFIG_NXP_S32_WKPU_SOURCES_MAX);
147 
148 	/* Disable triggers */
149 	REG_WRITE(WKPU_WIREER(reg_idx), REG_READ(WKPU_WIREER(reg_idx)) & ~mask);
150 	REG_WRITE(WKPU_WIFEER(reg_idx), REG_READ(WKPU_WIFEER(reg_idx)) & ~mask);
151 
152 	/* Clear status flag and mask interrupt */
153 	REG_WRITE(WKPU_WISR(reg_idx), REG_READ(WKPU_WISR(reg_idx)) | mask);
154 	REG_WRITE(WKPU_IRER(reg_idx), REG_READ(WKPU_IRER(reg_idx)) & ~mask);
155 }
156 
wkpu_nxp_s32_get_pending(const struct device * dev)157 uint64_t wkpu_nxp_s32_get_pending(const struct device *dev)
158 {
159 	const struct wkpu_nxp_s32_config *config = dev->config;
160 	uint64_t flags;
161 
162 	flags = REG_READ(WKPU_WISR(0U)) & REG_READ(WKPU_IRER(0U));
163 	if (CONFIG_NXP_S32_WKPU_SOURCES_MAX > 32U) {
164 		flags |= ((uint64_t)(REG_READ(WKPU_WISR(1U)) & REG_READ(WKPU_IRER(1U)))) << 32U;
165 	}
166 
167 	return flags;
168 }
169 
wkpu_nxp_s32_init(const struct device * dev)170 static int wkpu_nxp_s32_init(const struct device *dev)
171 {
172 	const struct wkpu_nxp_s32_config *config = dev->config;
173 
174 	/* Disable triggers, clear status flags and mask all interrupts */
175 	REG_WRITE(WKPU_WIREER(0U), 0U);
176 	REG_WRITE(WKPU_WIFEER(0U), 0U);
177 	REG_WRITE(WKPU_WISR(0U), 0xffffffff);
178 	REG_WRITE(WKPU_IRER(0U), 0U);
179 
180 	/* Configure glitch filters */
181 	REG_WRITE(WKPU_WIFER(0U), (uint32_t)config->filter_enable);
182 
183 	if (CONFIG_NXP_S32_WKPU_SOURCES_MAX > 32U) {
184 		REG_WRITE(WKPU_WIREER(1U), 0U);
185 		REG_WRITE(WKPU_WIFEER(1U), 0U);
186 		REG_WRITE(WKPU_WISR(1U), 0xffffffff);
187 		REG_WRITE(WKPU_IRER(1U), 0U);
188 		REG_WRITE(WKPU_WIFER(1U), (uint32_t)(config->filter_enable >> 32U));
189 	}
190 
191 	return 0;
192 }
193 
194 #define WKPU_NXP_S32_FILTER_CONFIG(idx, n)                                                         \
195 	COND_CODE_1(DT_PROP(DT_INST_CHILD(n, irq_##idx), filter_enable), (BIT(idx)), (0U))
196 
197 #define WKPU_NXP_S32_INIT_DEVICE(n)                                                                \
198 	static const struct wkpu_nxp_s32_config wkpu_nxp_s32_conf_##n = {                          \
199 		.base = DT_INST_REG_ADDR(n),                                                       \
200 		.filter_enable = LISTIFY(CONFIG_NXP_S32_WKPU_SOURCES_MAX,                          \
201 					 WKPU_NXP_S32_FILTER_CONFIG, (|), n),                      \
202 	};                                                                                         \
203 	static struct wkpu_nxp_s32_cb wkpu_nxp_s32_cb_##n[CONFIG_NXP_S32_WKPU_SOURCES_MAX];        \
204 	static struct wkpu_nxp_s32_data wkpu_nxp_s32_data_##n = {                                  \
205 		.cb = wkpu_nxp_s32_cb_##n,                                                         \
206 	};                                                                                         \
207 	static int wkpu_nxp_s32_init_##n(const struct device *dev)                                 \
208 	{                                                                                          \
209 		int err;                                                                           \
210                                                                                                    \
211 		err = wkpu_nxp_s32_init(dev);                                                      \
212 		if (err) {                                                                         \
213 			return err;                                                                \
214 		}                                                                                  \
215                                                                                                    \
216 		IRQ_CONNECT(DT_INST_IRQ(n, irq), DT_INST_IRQ(n, priority),                         \
217 			    wkpu_nxp_s32_interrupt_handler, DEVICE_DT_INST_GET(n),                 \
218 			    COND_CODE_1(CONFIG_GIC, (DT_INST_IRQ(n, flags)), (0U)));               \
219 		irq_enable(DT_INST_IRQ(n, irq));                                                   \
220                                                                                                    \
221 		return 0;                                                                          \
222 	}                                                                                          \
223 	DEVICE_DT_INST_DEFINE(n, wkpu_nxp_s32_init_##n, NULL, &wkpu_nxp_s32_data_##n,              \
224 			      &wkpu_nxp_s32_conf_##n, PRE_KERNEL_2, CONFIG_INTC_INIT_PRIORITY,     \
225 			      NULL);
226 
227 DT_INST_FOREACH_STATUS_OKAY(WKPU_NXP_S32_INIT_DEVICE)
228