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