1 /*
2 * Copyright (c) 2020, Antmicro <www.antmicro.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT quicklogic_eos_s3_gpio
8
9 #include <errno.h>
10 #include <zephyr/drivers/gpio.h>
11 #include <zephyr/irq.h>
12 #include <soc.h>
13 #include <eoss3_hal_gpio.h>
14 #include <eoss3_hal_pads.h>
15 #include <eoss3_hal_pad_config.h>
16
17 #include <zephyr/drivers/gpio/gpio_utils.h>
18
19 #define MAX_GPIOS 8U
20 #define GPIOS_MASK (BIT(MAX_GPIOS) - 1)
21 #define DISABLED_GPIO_IRQ 0xFFU
22
23 struct gpio_eos_s3_config {
24 /* gpio_driver_config needs to be first */
25 struct gpio_driver_config common;
26 /* Pin configuration to determine whether use primary
27 * or secondary pin for a target GPIO. Secondary pin is used
28 * when the proper bit is set to 1.
29 *
30 * bit_index : primary_pin_number / secondary_pin_number
31 *
32 * 0 : 6 / 24
33 * 1 : 9 / 26
34 * 2 : 11 / 28
35 * 3 : 14 / 30
36 * 4 : 18 / 31
37 * 5 : 21 / 36
38 * 6 : 22 / 38
39 * 7 : 23 / 45
40 */
41 uint8_t pin_secondary_config;
42 };
43
44 struct gpio_eos_s3_data {
45 /* gpio_driver_data needs to be first */
46 struct gpio_driver_data common;
47 /* port ISR callback routine address */
48 sys_slist_t callbacks;
49 /* array of interrupts mapped to the gpio number */
50 uint8_t gpio_irqs[MAX_GPIOS];
51 };
52
53 /* Connection table to configure GPIOs with pads */
54 static const PadConfig pad_configs[] = {
55 {.ucPin = PAD_6, .ucFunc = PAD6_FUNC_SEL_GPIO_0},
56 {.ucPin = PAD_9, .ucFunc = PAD9_FUNC_SEL_GPIO_1},
57 {.ucPin = PAD_11, .ucFunc = PAD11_FUNC_SEL_GPIO_2},
58 {.ucPin = PAD_14, .ucFunc = PAD14_FUNC_SEL_GPIO_3},
59 {.ucPin = PAD_18, .ucFunc = PAD18_FUNC_SEL_GPIO_4},
60 {.ucPin = PAD_21, .ucFunc = PAD21_FUNC_SEL_GPIO_5},
61 {.ucPin = PAD_22, .ucFunc = PAD22_FUNC_SEL_GPIO_6},
62 {.ucPin = PAD_23, .ucFunc = PAD23_FUNC_SEL_GPIO_7},
63 {.ucPin = PAD_24, .ucFunc = PAD24_FUNC_SEL_GPIO_0},
64 {.ucPin = PAD_26, .ucFunc = PAD26_FUNC_SEL_GPIO_1},
65 {.ucPin = PAD_28, .ucFunc = PAD28_FUNC_SEL_GPIO_2},
66 {.ucPin = PAD_30, .ucFunc = PAD30_FUNC_SEL_GPIO_3},
67 {.ucPin = PAD_31, .ucFunc = PAD31_FUNC_SEL_GPIO_4},
68 {.ucPin = PAD_36, .ucFunc = PAD36_FUNC_SEL_GPIO_5},
69 {.ucPin = PAD_38, .ucFunc = PAD38_FUNC_SEL_GPIO_6},
70 {.ucPin = PAD_45, .ucFunc = PAD45_FUNC_SEL_GPIO_7},
71 };
72
gpio_eos_s3_pad_select(const struct device * dev,uint8_t gpio_num)73 static PadConfig gpio_eos_s3_pad_select(const struct device *dev,
74 uint8_t gpio_num)
75 {
76 const struct gpio_eos_s3_config *config = dev->config;
77 uint8_t is_secondary = (config->pin_secondary_config >> gpio_num) & 1;
78
79 return pad_configs[(MAX_GPIOS * is_secondary) + gpio_num];
80 }
81
82 /* This function maps pad number to IRQ number */
gpio_eos_s3_get_irq_num(uint8_t pad)83 static int gpio_eos_s3_get_irq_num(uint8_t pad)
84 {
85 int gpio_irq_num;
86
87 switch (pad) {
88 case PAD_6:
89 gpio_irq_num = 1;
90 break;
91 case PAD_9:
92 gpio_irq_num = 3;
93 break;
94 case PAD_11:
95 gpio_irq_num = 5;
96 break;
97 case PAD_14:
98 gpio_irq_num = 5;
99 break;
100 case PAD_18:
101 gpio_irq_num = 1;
102 break;
103 case PAD_21:
104 gpio_irq_num = 2;
105 break;
106 case PAD_22:
107 gpio_irq_num = 3;
108 break;
109 case PAD_23:
110 gpio_irq_num = 7;
111 break;
112 case PAD_24:
113 gpio_irq_num = 1;
114 break;
115 case PAD_26:
116 gpio_irq_num = 4;
117 break;
118 case PAD_28:
119 gpio_irq_num = 3;
120 break;
121 case PAD_30:
122 gpio_irq_num = 5;
123 break;
124 case PAD_31:
125 gpio_irq_num = 6;
126 break;
127 case PAD_36:
128 gpio_irq_num = 1;
129 break;
130 case PAD_38:
131 gpio_irq_num = 2;
132 break;
133 case PAD_45:
134 gpio_irq_num = 5;
135 break;
136 default:
137 return -EINVAL;
138 }
139
140 return gpio_irq_num;
141 }
142
gpio_eos_s3_configure(const struct device * dev,gpio_pin_t gpio_num,gpio_flags_t flags)143 static int gpio_eos_s3_configure(const struct device *dev,
144 gpio_pin_t gpio_num,
145 gpio_flags_t flags)
146 {
147 uint32_t *io_mux = (uint32_t *)IO_MUX;
148 GPIOCfgTypeDef gpio_cfg;
149 PadConfig pad_config = gpio_eos_s3_pad_select(dev, gpio_num);
150
151 if (flags & GPIO_SINGLE_ENDED) {
152 return -ENOTSUP;
153 }
154
155 gpio_cfg.ucGpioNum = gpio_num;
156 gpio_cfg.xPadConf = &pad_config;
157
158 /* Configure PAD */
159 if (flags & GPIO_PULL_UP) {
160 gpio_cfg.xPadConf->ucPull = PAD_PULLUP;
161 } else if (flags & GPIO_PULL_DOWN) {
162 gpio_cfg.xPadConf->ucPull = PAD_PULLDOWN;
163 } else {
164 /* High impedance */
165 gpio_cfg.xPadConf->ucPull = PAD_NOPULL;
166 }
167
168 if ((flags & GPIO_INPUT) != 0) {
169 gpio_cfg.xPadConf->ucMode = PAD_MODE_INPUT_EN;
170 gpio_cfg.xPadConf->ucSmtTrg = PAD_SMT_TRIG_EN;
171 }
172
173 if ((flags & GPIO_OUTPUT) != 0) {
174 if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
175 MISC_CTRL->IO_OUTPUT |= (BIT(gpio_num) & GPIOS_MASK);
176 } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
177 MISC_CTRL->IO_OUTPUT &= ~(BIT(gpio_num) & GPIOS_MASK);
178 }
179 gpio_cfg.xPadConf->ucMode = PAD_MODE_OUTPUT_EN;
180 }
181
182 if (flags == GPIO_DISCONNECTED) {
183 gpio_cfg.xPadConf->ucMode = PAD_MODE_INPUT_EN;
184 gpio_cfg.xPadConf->ucSmtTrg = PAD_SMT_TRIG_DIS;
185 }
186
187 /* Initial PAD configuration */
188 HAL_PAD_Config(gpio_cfg.xPadConf);
189
190 /* Override direction setup to support bidirectional config */
191 if ((flags & GPIO_DIR_MASK) == (GPIO_INPUT | GPIO_OUTPUT)) {
192 io_mux += gpio_cfg.xPadConf->ucPin;
193 *io_mux &= ~PAD_OEN_DISABLE;
194 *io_mux |= PAD_REN_ENABLE;
195 }
196
197 return 0;
198 }
199
gpio_eos_s3_port_get_raw(const struct device * dev,uint32_t * value)200 static int gpio_eos_s3_port_get_raw(const struct device *dev,
201 uint32_t *value)
202 {
203 ARG_UNUSED(dev);
204
205 *value = (MISC_CTRL->IO_INPUT & GPIOS_MASK);
206
207 return 0;
208 }
209
gpio_eos_s3_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)210 static int gpio_eos_s3_port_set_masked_raw(const struct device *dev,
211 uint32_t mask,
212 uint32_t value)
213 {
214 ARG_UNUSED(dev);
215 uint32_t target_value;
216 uint32_t output_states = MISC_CTRL->IO_OUTPUT;
217
218 target_value = ((output_states & ~mask) | (value & mask));
219 MISC_CTRL->IO_OUTPUT = (target_value & GPIOS_MASK);
220
221 return 0;
222 }
223
gpio_eos_s3_port_set_bits_raw(const struct device * dev,uint32_t mask)224 static int gpio_eos_s3_port_set_bits_raw(const struct device *dev,
225 uint32_t mask)
226 {
227 ARG_UNUSED(dev);
228
229 MISC_CTRL->IO_OUTPUT |= (mask & GPIOS_MASK);
230
231 return 0;
232 }
233
gpio_eos_s3_port_clear_bits_raw(const struct device * dev,uint32_t mask)234 static int gpio_eos_s3_port_clear_bits_raw(const struct device *dev,
235 uint32_t mask)
236 {
237 ARG_UNUSED(dev);
238
239 MISC_CTRL->IO_OUTPUT &= ~(mask & GPIOS_MASK);
240
241 return 0;
242 }
243
gpio_eos_s3_port_toggle_bits(const struct device * dev,uint32_t mask)244 static int gpio_eos_s3_port_toggle_bits(const struct device *dev,
245 uint32_t mask)
246 {
247 ARG_UNUSED(dev);
248 uint32_t target_value;
249 uint32_t output_states = MISC_CTRL->IO_OUTPUT;
250
251 target_value = output_states ^ mask;
252 MISC_CTRL->IO_OUTPUT = (target_value & GPIOS_MASK);
253
254 return 0;
255 }
256
gpio_eos_s3_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)257 static int gpio_eos_s3_manage_callback(const struct device *dev,
258 struct gpio_callback *callback, bool set)
259 {
260 struct gpio_eos_s3_data *data = dev->data;
261
262 return gpio_manage_callback(&data->callbacks, callback, set);
263 }
264
gpio_eos_s3_pin_interrupt_configure(const struct device * dev,gpio_pin_t gpio_num,enum gpio_int_mode mode,enum gpio_int_trig trig)265 static int gpio_eos_s3_pin_interrupt_configure(const struct device *dev,
266 gpio_pin_t gpio_num,
267 enum gpio_int_mode mode,
268 enum gpio_int_trig trig)
269 {
270 struct gpio_eos_s3_data *data = dev->data;
271 GPIOCfgTypeDef gpio_cfg;
272 PadConfig pad_config = gpio_eos_s3_pad_select(dev, gpio_num);
273
274 gpio_cfg.ucGpioNum = gpio_num;
275 gpio_cfg.xPadConf = &pad_config;
276
277 if (mode == GPIO_INT_MODE_DISABLED) {
278 /* Get IRQ number which should be disabled */
279 int irq_num = gpio_eos_s3_get_irq_num(pad_config.ucPin);
280
281 if (irq_num < 0) {
282 return -EINVAL;
283 }
284
285 /* Disable IRQ */
286 INTR_CTRL->GPIO_INTR_EN_M4 &= ~BIT((uint32_t)irq_num);
287
288 /* Mark corresponding IRQ number as disabled */
289 data->gpio_irqs[irq_num] = DISABLED_GPIO_IRQ;
290
291 /* Clear configuration */
292 INTR_CTRL->GPIO_INTR_TYPE &= ~((uint32_t)(BIT(irq_num)));
293 INTR_CTRL->GPIO_INTR_POL &= ~((uint32_t)(BIT(irq_num)));
294 } else {
295 /* Prepare configuration */
296 if (mode == GPIO_INT_MODE_LEVEL) {
297 gpio_cfg.intr_type = LEVEL_TRIGGERED;
298 if (trig == GPIO_INT_TRIG_LOW) {
299 gpio_cfg.pol_type = FALL_LOW;
300 } else {
301 gpio_cfg.pol_type = RISE_HIGH;
302 }
303 } else {
304 gpio_cfg.intr_type = EDGE_TRIGGERED;
305 switch (trig) {
306 case GPIO_INT_TRIG_LOW:
307 gpio_cfg.pol_type = FALL_LOW;
308 break;
309 case GPIO_INT_TRIG_HIGH:
310 gpio_cfg.pol_type = RISE_HIGH;
311 break;
312 case GPIO_INT_TRIG_BOTH:
313 return -ENOTSUP;
314 }
315 }
316
317 /* Set IRQ configuration */
318 int irq_num = HAL_GPIO_IntrCfg(&gpio_cfg);
319
320 if (irq_num < 0) {
321 return -EINVAL;
322 }
323
324 /* Set corresponding IRQ number as enabled */
325 data->gpio_irqs[irq_num] = gpio_num;
326
327 /* Clear pending GPIO interrupts */
328 INTR_CTRL->GPIO_INTR |= BIT((uint32_t)irq_num);
329
330 /* Enable IRQ */
331 INTR_CTRL->GPIO_INTR_EN_M4 |= BIT((uint32_t)irq_num);
332 }
333
334 return 0;
335 }
336
gpio_eos_s3_isr(const struct device * dev)337 static void gpio_eos_s3_isr(const struct device *dev)
338 {
339 struct gpio_eos_s3_data *data = dev->data;
340 /* Level interrupts can be only checked from read-only GPIO_INTR_RAW,
341 * we need to add it to the intr_status.
342 */
343 uint32_t intr_status = (INTR_CTRL->GPIO_INTR | INTR_CTRL->GPIO_INTR_RAW);
344
345 /* Clear pending GPIO interrupts */
346 INTR_CTRL->GPIO_INTR |= intr_status;
347
348 /* Fire callbacks */
349 for (int irq_num = 0; irq_num < MAX_GPIOS; irq_num++) {
350 if (data->gpio_irqs[irq_num] != DISABLED_GPIO_IRQ) {
351 gpio_fire_callbacks(&data->callbacks,
352 dev, BIT(data->gpio_irqs[irq_num]));
353 }
354 }
355 }
356
357 #ifdef CONFIG_GPIO_GET_DIRECTION
gpio_eos_s3_port_get_direction(const struct device * port,gpio_port_pins_t map,gpio_port_pins_t * inputs,gpio_port_pins_t * outputs)358 static int gpio_eos_s3_port_get_direction(const struct device *port, gpio_port_pins_t map,
359 gpio_port_pins_t *inputs, gpio_port_pins_t *outputs)
360 {
361 uint32_t pin;
362 PadConfig pad_config;
363 gpio_port_pins_t ip = 0;
364 gpio_port_pins_t op = 0;
365 const struct gpio_eos_s3_config *config = dev->config;
366
367 map &= config->common.port_pin_mask;
368
369 if (inputs != NULL) {
370 for (pin = find_lsb_set(pins) - 1; pins;
371 pins &= ~BIT(pin), pin = find_lsb_set(pins) - 1) {
372 pad_config = gpio_eos_s3_pad_select(port, pin);
373 ip |= (pad_config.ucMode == PAD_MODE_INPUT_EN &&
374 pad_config.ucSmtTrg == PAD_SMT_TRIG_EN) *
375 BIT(pin);
376 }
377
378 *inputs = ip;
379 }
380
381 if (outputs != NULL) {
382 for (pin = find_lsb_set(pins) - 1; pins;
383 pins &= ~BIT(pin), pin = find_lsb_set(pins) - 1) {
384 pad_config = gpio_eos_s3_pad_select(port, pin);
385 op |= (pad_config.ucMode == PAD_MODE_OUTPUT_EN) * BIT(pin);
386 }
387
388 *outputs = op;
389 }
390
391 return 0;
392 }
393 #endif /* CONFIG_GPIO_GET_DIRECTION */
394
395 static const struct gpio_driver_api gpio_eos_s3_driver_api = {
396 .pin_configure = gpio_eos_s3_configure,
397 .port_get_raw = gpio_eos_s3_port_get_raw,
398 .port_set_masked_raw = gpio_eos_s3_port_set_masked_raw,
399 .port_set_bits_raw = gpio_eos_s3_port_set_bits_raw,
400 .port_clear_bits_raw = gpio_eos_s3_port_clear_bits_raw,
401 .port_toggle_bits = gpio_eos_s3_port_toggle_bits,
402 .pin_interrupt_configure = gpio_eos_s3_pin_interrupt_configure,
403 .manage_callback = gpio_eos_s3_manage_callback,
404 #ifdef CONFIG_GPIO_GET_DIRECTION
405 .port_get_direction = gpio_eos_s3_port_get_direction,
406 #endif /* CONFIG_GPIO_GET_DIRECTION */
407 };
408
gpio_eos_s3_init(const struct device * dev)409 static int gpio_eos_s3_init(const struct device *dev)
410 {
411 ARG_UNUSED(dev);
412 IRQ_CONNECT(DT_INST_IRQN(0),
413 DT_INST_IRQ(0, priority),
414 gpio_eos_s3_isr,
415 DEVICE_DT_INST_GET(0),
416 0);
417
418 irq_enable(DT_INST_IRQN(0));
419
420 return 0;
421 }
422
423 const struct gpio_eos_s3_config gpio_eos_s3_config = {
424 .common = {
425 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0),
426 },
427 .pin_secondary_config = DT_INST_PROP(0, pin_secondary_config),
428 };
429
430 static struct gpio_eos_s3_data gpio_eos_s3_data = {
431 .gpio_irqs = {
432 DISABLED_GPIO_IRQ,
433 DISABLED_GPIO_IRQ,
434 DISABLED_GPIO_IRQ,
435 DISABLED_GPIO_IRQ,
436 DISABLED_GPIO_IRQ,
437 DISABLED_GPIO_IRQ,
438 DISABLED_GPIO_IRQ,
439 DISABLED_GPIO_IRQ
440 },
441 };
442
443 DEVICE_DT_INST_DEFINE(0,
444 gpio_eos_s3_init,
445 NULL,
446 &gpio_eos_s3_data,
447 &gpio_eos_s3_config,
448 PRE_KERNEL_1,
449 CONFIG_GPIO_INIT_PRIORITY,
450 &gpio_eos_s3_driver_api);
451