1 /*
2  * Copyright (c) 2023 Efinix Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT efinix_sapphire_gpio
8 
9 #include <zephyr/drivers/gpio/gpio_utils.h>
10 
11 #include <errno.h>
12 #include <string.h>
13 
14 #include <zephyr/device.h>
15 #include <zephyr/drivers/gpio.h>
16 #include <zephyr/logging/log.h>
17 #include <zephyr/sys/util.h>
18 #include <zephyr/types.h>
19 
20 LOG_MODULE_REGISTER(gpio_efinix_sapphire);
21 
22 #define SUPPORTED_FLAGS                                                                            \
23 	(GPIO_INPUT | GPIO_OUTPUT | GPIO_OUTPUT_INIT_LOW | GPIO_OUTPUT_INIT_HIGH |                 \
24 	 GPIO_ACTIVE_LOW | GPIO_ACTIVE_HIGH)
25 
26 #define GPIO_LOW  0
27 #define GPIO_HIGH 1
28 
29 #define BSP_GPIO_INPUT                 0x00
30 #define BSP_GPIO_OUTPUT                0x04
31 #define BSP_GPIO_OUTPUT_ENABLE         0x08
32 #define BSP_GPIO_INTERRUPT_RISE_ENABLE 0x20
33 #define BSP_GPIO_INTERRUPT_FALL_ENABLE 0x24
34 #define BSP_GPIO_INTERRUPT_HIGH_ENABLE 0x28
35 #define BSP_GPIO_INTERRUPT_LOW_ENABLE  0x2c
36 
37 /* efinix sapphire specific gpio config struct */
38 struct gpio_efinix_sapphire_cfg {
39 	uint32_t base_addr;
40 	int n_gpios;
41 	struct gpio_driver_config common;
42 };
43 
44 /* efinix sapphire specific gpio data struct */
45 struct gpio_efinix_sapphire_data {
46 	struct gpio_driver_data common;
47 	const struct device *dev;
48 	sys_slist_t cb;
49 };
50 
51 /* Device access pointer helpers */
52 #define DEV_GPIO_CFG(dev) ((const struct gpio_efinix_sapphire_cfg *)(dev)->config)
53 #define GPIO_OUTPUT_ADDR  config->base_addr + BSP_GPIO_OUTPUT
54 
cfg_output_enable_bit(const struct gpio_efinix_sapphire_cfg * config,gpio_pin_t pin,uint32_t type)55 static inline void cfg_output_enable_bit(const struct gpio_efinix_sapphire_cfg *config,
56 					 gpio_pin_t pin, uint32_t type)
57 {
58 
59 #define GPIO_OUTPUT_ENABLE_ADDR config->base_addr + BSP_GPIO_OUTPUT_ENABLE
60 	uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ENABLE_ADDR);
61 
62 	if (type == GPIO_INPUT) {
63 		sys_write32(c_reg_val &= ~pin, GPIO_OUTPUT_ENABLE_ADDR);
64 	} else if (type == GPIO_OUTPUT) {
65 		sys_write32(c_reg_val |= pin, GPIO_OUTPUT_ENABLE_ADDR);
66 	}
67 }
68 
cfg_output_bit(const struct gpio_efinix_sapphire_cfg * config,gpio_pin_t pin,uint32_t value)69 static inline void cfg_output_bit(const struct gpio_efinix_sapphire_cfg *config, gpio_pin_t pin,
70 				  uint32_t value)
71 {
72 
73 	uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ADDR);
74 
75 	if (value == GPIO_LOW) {
76 		sys_write32(c_reg_val &= ~pin, GPIO_OUTPUT_ADDR);
77 	} else if (value == GPIO_HIGH) {
78 		sys_write32(c_reg_val |= pin, GPIO_OUTPUT_ADDR);
79 	}
80 }
81 
82 /* To use the controller bare minimum as IO, Peripheral has to configure, */
83 /* the Output enable register, b0 : Input, b1 : Output */
84 
gpio_efinix_sapphire_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)85 static int gpio_efinix_sapphire_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
86 {
87 	const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev);
88 	/* Check if the controller supports the requested GPIO configuration.  */
89 	if (flags & ~SUPPORTED_FLAGS) {
90 		return -ENOTSUP;
91 	}
92 
93 	if ((flags & GPIO_DIR_MASK) == GPIO_DIR_MASK) {
94 		/* Pin cannot be configured as input and output */
95 		return -ENOTSUP;
96 	} else if ((flags & GPIO_DIR_MASK) == GPIO_DISCONNECTED) {
97 		/* Pin has to be configured as input or output */
98 		return -ENOTSUP;
99 	}
100 
101 	/* Configure the output register based on the direction flag */
102 	if (flags & GPIO_OUTPUT) {
103 		/* Set the pin as output */
104 		cfg_output_enable_bit(config, BIT(pin), GPIO_OUTPUT);
105 		if (flags & GPIO_OUTPUT_INIT_HIGH) {
106 			/* Set the pin to high */
107 			cfg_output_bit(config, BIT(pin), GPIO_HIGH);
108 		} else if (flags & GPIO_OUTPUT_INIT_LOW) {
109 			/* Set the pin to low */
110 			cfg_output_bit(config, BIT(pin), GPIO_LOW);
111 		}
112 	} else {
113 		/* Set the pin as input */
114 		cfg_output_enable_bit(config, BIT(pin), GPIO_INPUT);
115 	}
116 
117 	return 0;
118 }
119 
get_port(const struct gpio_efinix_sapphire_cfg * config)120 static inline uint32_t get_port(const struct gpio_efinix_sapphire_cfg *config)
121 {
122 	uint32_t c_reg_val = sys_read32(GPIO_OUTPUT_ADDR);
123 
124 	return (c_reg_val & BIT_MASK(config->n_gpios));
125 }
126 
set_port(const struct gpio_efinix_sapphire_cfg * config,uint32_t value)127 static inline void set_port(const struct gpio_efinix_sapphire_cfg *config, uint32_t value)
128 {
129 	sys_write32(value, GPIO_OUTPUT_ADDR);
130 }
131 
gpio_efinix_sapphire_port_get_raw(const struct device * dev,gpio_port_value_t * value)132 static int gpio_efinix_sapphire_port_get_raw(const struct device *dev, gpio_port_value_t *value)
133 {
134 	const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev);
135 
136 	*value = get_port(config);
137 	return 0;
138 }
139 
gpio_efinix_sapphire_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)140 static int gpio_efinix_sapphire_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask,
141 						    gpio_port_value_t value)
142 {
143 	const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev);
144 
145 	uint32_t c_reg_val = get_port(config);
146 
147 	/* Sets ports value at one go */
148 	c_reg_val &= ~mask;
149 	c_reg_val |= (value & mask);
150 
151 	set_port(config, c_reg_val);
152 
153 	return 0;
154 }
155 
gpio_efinix_sapphire_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)156 static int gpio_efinix_sapphire_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins)
157 {
158 	const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev);
159 
160 	uint32_t c_reg_val = get_port(config);
161 
162 	/* Sets ports value at one go */
163 	c_reg_val |= pins;
164 
165 	set_port(config, c_reg_val);
166 
167 	return 0;
168 }
169 
gpio_efinix_sapphire_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)170 static int gpio_efinix_sapphire_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins)
171 {
172 	const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev);
173 
174 	uint32_t c_reg_val = get_port(config);
175 
176 	/* Sets ports value at one go */
177 	c_reg_val &= ~pins;
178 
179 	set_port(config, c_reg_val);
180 
181 	return 0;
182 }
183 
gpio_efinix_sapphire_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)184 static int gpio_efinix_sapphire_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
185 {
186 	const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev);
187 
188 	uint32_t c_reg_val = get_port(config);
189 
190 	/* Sets ports value at one go */
191 	c_reg_val ^= pins;
192 
193 	set_port(config, c_reg_val);
194 
195 	return 0;
196 }
197 
gpio_efinix_sapphire_init(const struct device * dev)198 static int gpio_efinix_sapphire_init(const struct device *dev)
199 {
200 	const struct gpio_efinix_sapphire_cfg *config = DEV_GPIO_CFG(dev);
201 
202 	if (config->n_gpios > 4) {
203 		return -EINVAL;
204 	}
205 	return 0;
206 }
207 
208 /* API map */
209 static const struct gpio_driver_api gpio_efinix_sapphire_api = {
210 	.pin_configure = gpio_efinix_sapphire_config,
211 	.port_get_raw = gpio_efinix_sapphire_port_get_raw,
212 	.port_set_masked_raw = gpio_efinix_sapphire_port_set_masked_raw,
213 	.port_set_bits_raw = gpio_efinix_sapphire_port_set_bits_raw,
214 	.port_clear_bits_raw = gpio_efinix_sapphire_port_clear_bits_raw,
215 	.port_toggle_bits = gpio_efinix_sapphire_port_toggle_bits,
216 };
217 
218 #define GPIO_EFINIX_SAPPHIRE_INIT(n) \
219 	static struct gpio_efinix_sapphire_cfg gpio_efinix_sapphire_cfg_##n = { \
220 		.base_addr = DT_INST_REG_ADDR(n), \
221 		.n_gpios = DT_INST_PROP(n, ngpios), \
222 }; \
223 static struct gpio_efinix_sapphire_data gpio_efinix_sapphire_data_##n; \
224 	DEVICE_DT_INST_DEFINE(n, \
225 			    gpio_efinix_sapphire_init, \
226 			    NULL, \
227 			    &gpio_efinix_sapphire_data_##n, \
228 			    &gpio_efinix_sapphire_cfg_##n, \
229 			    POST_KERNEL, \
230 			    CONFIG_GPIO_INIT_PRIORITY, \
231 			    &gpio_efinix_sapphire_api \
232 				); \
233 
234 DT_INST_FOREACH_STATUS_OKAY(GPIO_EFINIX_SAPPHIRE_INIT)
235