1 /*
2 * Copyright (c) 2022, Renesas Electronics Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT renesas_smartbond_gpio
8
9 #include <zephyr/drivers/gpio/gpio_utils.h>
10
11 #include <stdint.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/irq.h>
14
15 #include <DA1469xAB.h>
16 #include <da1469x_pdc.h>
17
18 #define GPIO_MODE_RESET 0x200
19
20 #define GPIO_PUPD_INPUT 0
21 #define GPIO_PUPD_INPUT_PU 1
22 #define GPIO_PUPD_INPUT_PD 2
23 #define GPIO_PUPD_OUTPUT 3
24
25 /* GPIO P0 and P1 share single GPIO and WKUP peripheral instance with separate
26 * set registers for P0 and P1 interleaved. The starting registers for direct
27 * data access, bit access, mode, latch and wake-up controller are defined in
28 * device tree.
29 */
30
31 struct gpio_smartbond_data_regs {
32 uint32_t data;
33 uint32_t _reserved0;
34 uint32_t set;
35 uint32_t _reserved1;
36 uint32_t reset;
37 };
38
39 struct gpio_smartbond_latch_regs {
40 uint32_t latch;
41 uint32_t set;
42 uint32_t reset;
43 };
44
45 struct gpio_smartbond_wkup_regs {
46 uint32_t select;
47 uint32_t _reserved0[4];
48 uint32_t pol;
49 uint32_t _reserved1[4];
50 uint32_t status;
51 uint32_t _reserved2[2];
52 uint32_t clear;
53 uint32_t _reserved3[2];
54 uint32_t sel;
55 };
56
57 struct gpio_smartbond_data {
58 /* gpio_driver_data needs to be first */
59 struct gpio_driver_data common;
60 /* Pins that are configured for both edges (handled by software) */
61 gpio_port_pins_t both_edges_pins;
62 sys_slist_t callbacks;
63 };
64
65 struct gpio_smartbond_config {
66 /* gpio_driver_config needs to be first */
67 struct gpio_driver_config common;
68 volatile struct gpio_smartbond_data_regs *data_regs;
69 volatile uint32_t *mode_regs;
70 volatile struct gpio_smartbond_latch_regs *latch_regs;
71 volatile struct gpio_smartbond_wkup_regs *wkup_regs;
72 /* Value of TRIG_SELECT for PDC_CTRLx_REG entry */
73 uint8_t wkup_trig_select;
74 };
75
gpio_smartbond_wkup_init(void)76 static void gpio_smartbond_wkup_init(void)
77 {
78 static bool wkup_init;
79
80 /* Wakeup controller is shared for both GPIO ports and should
81 * be initialized only once.
82 */
83 if (!wkup_init) {
84 WAKEUP->WKUP_CTRL_REG = 0;
85 WAKEUP->WKUP_CLEAR_P0_REG = 0xffffffff;
86 WAKEUP->WKUP_CLEAR_P1_REG = 0xffffffff;
87 WAKEUP->WKUP_SELECT_P0_REG = 0;
88 WAKEUP->WKUP_SELECT_P1_REG = 0;
89 WAKEUP->WKUP_SEL_GPIO_P0_REG = 0;
90 WAKEUP->WKUP_SEL_GPIO_P1_REG = 0;
91 WAKEUP->WKUP_RESET_IRQ_REG = 0;
92
93 CRG_TOP->CLK_TMR_REG |= CRG_TOP_CLK_TMR_REG_WAKEUPCT_ENABLE_Msk;
94
95 WAKEUP->WKUP_CTRL_REG = WAKEUP_WKUP_CTRL_REG_WKUP_ENABLE_IRQ_Msk;
96
97 wkup_init = true;
98 }
99 }
100
gpio_smartbond_pin_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)101 static int gpio_smartbond_pin_configure(const struct device *dev,
102 gpio_pin_t pin, gpio_flags_t flags)
103 {
104 const struct gpio_smartbond_config *config = dev->config;
105
106 if (flags == GPIO_DISCONNECTED) {
107 /* Reset to default value */
108 config->mode_regs[pin] = GPIO_MODE_RESET;
109 return 0;
110 }
111
112 if ((flags & GPIO_INPUT) && (flags & GPIO_OUTPUT)) {
113 /* Simultaneous in/out is not supported */
114 return -ENOTSUP;
115 }
116
117 if (flags & GPIO_OUTPUT) {
118 config->mode_regs[pin] = GPIO_PUPD_OUTPUT << GPIO_P0_00_MODE_REG_PUPD_Pos;
119
120 if (flags & GPIO_OUTPUT_INIT_LOW) {
121 config->data_regs->reset = BIT(pin);
122 } else if (flags & GPIO_OUTPUT_INIT_HIGH) {
123 config->data_regs->set = BIT(pin);
124 }
125
126 return 0;
127 }
128
129 if (flags & GPIO_PULL_DOWN) {
130 config->mode_regs[pin] = GPIO_PUPD_INPUT_PD << GPIO_P0_00_MODE_REG_PUPD_Pos;
131 } else if (flags & GPIO_PULL_UP) {
132 config->mode_regs[pin] = GPIO_PUPD_INPUT_PU << GPIO_P0_00_MODE_REG_PUPD_Pos;
133 } else {
134 config->mode_regs[pin] = GPIO_PUPD_INPUT << GPIO_P0_00_MODE_REG_PUPD_Pos;
135 }
136
137 return 0;
138 }
139
gpio_smartbond_port_get_raw(const struct device * dev,gpio_port_value_t * value)140 static int gpio_smartbond_port_get_raw(const struct device *dev,
141 gpio_port_value_t *value)
142 {
143 const struct gpio_smartbond_config *config = dev->config;
144
145 *value = config->data_regs->data;
146
147 return 0;
148 }
149
gpio_smartbond_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)150 static int gpio_smartbond_port_set_masked_raw(const struct device *dev,
151 gpio_port_pins_t mask,
152 gpio_port_value_t value)
153 {
154 const struct gpio_smartbond_config *config = dev->config;
155
156 config->data_regs->data = value & mask;
157
158 return 0;
159 }
160
gpio_smartbond_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)161 static int gpio_smartbond_port_set_bits_raw(const struct device *dev,
162 gpio_port_pins_t pins)
163 {
164 const struct gpio_smartbond_config *config = dev->config;
165
166 config->data_regs->set = pins;
167
168 return 0;
169 }
170
gpio_smartbond_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)171 static int gpio_smartbond_port_clear_bits_raw(const struct device *dev,
172 gpio_port_pins_t pins)
173 {
174 const struct gpio_smartbond_config *config = dev->config;
175
176 config->data_regs->reset = pins;
177
178 return 0;
179 }
180
gpio_smartbond_port_toggle_bits(const struct device * dev,gpio_port_pins_t mask)181 static int gpio_smartbond_port_toggle_bits(const struct device *dev,
182 gpio_port_pins_t mask)
183 {
184 const struct gpio_smartbond_config *config = dev->config;
185 volatile uint32_t *reg = &config->data_regs->data;
186
187 *reg = *reg ^ mask;
188
189 return 0;
190 }
191
gpio_smartbond_arm_next_edge_interrupt(const struct device * dev,uint32_t pin_mask)192 static void gpio_smartbond_arm_next_edge_interrupt(const struct device *dev,
193 uint32_t pin_mask)
194 {
195 const struct gpio_smartbond_config *config = dev->config;
196 uint32_t pin_value;
197
198 do {
199 pin_value = config->data_regs->data & pin_mask;
200 if (pin_value) {
201 config->wkup_regs->pol |= pin_mask;
202 } else {
203 config->wkup_regs->pol &= ~pin_mask;
204 }
205 } while (pin_value != (config->data_regs->data & pin_mask));
206 }
207
gpio_smartbond_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)208 static int gpio_smartbond_pin_interrupt_configure(const struct device *dev,
209 gpio_pin_t pin,
210 enum gpio_int_mode mode,
211 enum gpio_int_trig trig)
212 {
213 const struct gpio_smartbond_config *config = dev->config;
214 struct gpio_smartbond_data *data = dev->data;
215 uint32_t pin_mask = BIT(pin);
216 #if CONFIG_PM
217 int trig_select_id = (config->wkup_trig_select << 5) | pin;
218 int pdc_ix;
219 #endif
220
221 /* Not supported by hardware */
222 if (mode == GPIO_INT_MODE_LEVEL) {
223 return -ENOTSUP;
224 }
225
226 #if CONFIG_PM
227 pdc_ix = da1469x_pdc_find(trig_select_id, MCU_PDC_MASTER_M33, MCU_PDC_EN_XTAL);
228 #endif
229 if (mode == GPIO_INT_MODE_DISABLED) {
230 config->wkup_regs->sel &= ~pin_mask;
231 config->wkup_regs->clear = pin_mask;
232 data->both_edges_pins &= ~pin_mask;
233 #if CONFIG_PM
234 da1469x_pdc_del(pdc_ix);
235 #endif
236 } else {
237 if (trig == GPIO_INT_TRIG_BOTH) {
238 /* Not supported by hardware */
239 data->both_edges_pins |= pin_mask;
240 gpio_smartbond_arm_next_edge_interrupt(dev, pin_mask);
241 } else if (trig == GPIO_INT_TRIG_HIGH) {
242 config->wkup_regs->pol &= ~pin_mask;
243 } else {
244 config->wkup_regs->pol |= pin_mask;
245 }
246
247 config->wkup_regs->sel |= pin_mask;
248 #if CONFIG_PM
249 if (pdc_ix < 0) {
250 pdc_ix = da1469x_pdc_add(trig_select_id, MCU_PDC_MASTER_M33,
251 MCU_PDC_EN_XTAL);
252 }
253 if (pdc_ix < 0) {
254 return -ENOMEM;
255 }
256 #endif
257 }
258
259 return 0;
260 }
261
gpio_smartbond_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)262 static int gpio_smartbond_manage_callback(const struct device *dev,
263 struct gpio_callback *callback, bool set)
264 {
265 struct gpio_smartbond_data *data = dev->data;
266
267 return gpio_manage_callback(&data->callbacks, callback, set);
268 }
269
gpio_smartbond_isr(const struct device * dev)270 static void gpio_smartbond_isr(const struct device *dev)
271 {
272 const struct gpio_smartbond_config *config = dev->config;
273 struct gpio_smartbond_data *data = dev->data;
274 uint32_t stat;
275 uint32_t two_edge_triggered;
276
277 WAKEUP->WKUP_RESET_IRQ_REG = WAKEUP_WKUP_RESET_IRQ_REG_WKUP_IRQ_RST_Msk;
278
279 stat = config->wkup_regs->status;
280
281 two_edge_triggered = stat & data->both_edges_pins;
282 while (two_edge_triggered) {
283 int pos = find_lsb_set(two_edge_triggered) - 1;
284
285 two_edge_triggered &= ~BIT(pos);
286 /* Re-arm for other edge */
287 gpio_smartbond_arm_next_edge_interrupt(dev, BIT(pos));
288 }
289
290 config->wkup_regs->clear = stat;
291
292 gpio_fire_callbacks(&data->callbacks, dev, stat);
293 }
294
295 /* GPIO driver registration */
296 static const struct gpio_driver_api gpio_smartbond_drv_api_funcs = {
297 .pin_configure = gpio_smartbond_pin_configure,
298 .port_get_raw = gpio_smartbond_port_get_raw,
299 .port_set_masked_raw = gpio_smartbond_port_set_masked_raw,
300 .port_set_bits_raw = gpio_smartbond_port_set_bits_raw,
301 .port_clear_bits_raw = gpio_smartbond_port_clear_bits_raw,
302 .port_toggle_bits = gpio_smartbond_port_toggle_bits,
303 .pin_interrupt_configure = gpio_smartbond_pin_interrupt_configure,
304 .manage_callback = gpio_smartbond_manage_callback,
305 };
306
307 #define GPIO_SMARTBOND_DEVICE(id) \
308 static const struct gpio_smartbond_config gpio_smartbond_p##id##_config = { \
309 .common = { \
310 .port_pin_mask = \
311 GPIO_PORT_PIN_MASK_FROM_DT_INST(id), \
312 }, \
313 .data_regs = (volatile struct gpio_smartbond_data_regs *) \
314 DT_INST_REG_ADDR_BY_NAME(id, data), \
315 .mode_regs = (volatile uint32_t *)DT_INST_REG_ADDR_BY_NAME(id, mode), \
316 .latch_regs = (volatile struct gpio_smartbond_latch_regs *) \
317 DT_INST_REG_ADDR_BY_NAME(id, latch), \
318 .wkup_regs = (volatile struct gpio_smartbond_wkup_regs *) \
319 DT_INST_REG_ADDR_BY_NAME(id, wkup), \
320 .wkup_trig_select = id, \
321 }; \
322 \
323 static struct gpio_smartbond_data gpio_smartbond_p##id##_data; \
324 \
325 static int gpio_smartbond_##id##_init(const struct device *dev) \
326 { \
327 gpio_smartbond_wkup_init(); \
328 IRQ_CONNECT(DT_INST_IRQN(id), \
329 DT_INST_IRQ(id, priority), \
330 gpio_smartbond_isr, \
331 DEVICE_DT_INST_GET(id), 0); \
332 irq_enable(DT_INST_IRQN(id)); \
333 return 0; \
334 } \
335 \
336 DEVICE_DT_INST_DEFINE(id, gpio_smartbond_##id##_init, \
337 NULL, \
338 &gpio_smartbond_p##id##_data, \
339 &gpio_smartbond_p##id##_config, \
340 PRE_KERNEL_1, \
341 CONFIG_GPIO_INIT_PRIORITY, \
342 &gpio_smartbond_drv_api_funcs);
343
344 DT_INST_FOREACH_STATUS_OKAY(GPIO_SMARTBOND_DEVICE)
345