1 /* Copyright (c) 2023 Intel Corporation.
2  *
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT intel_sedi_gpio
7 
8 #include "sedi_driver_gpio.h"
9 #include <zephyr/drivers/gpio.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/drivers/gpio/gpio_utils.h>
12 #include <zephyr/pm/device.h>
13 
14 struct gpio_sedi_config {
15 	/* gpio_driver_data needs to be first */
16 	struct gpio_driver_config common;
17 	sedi_gpio_t device;
18 	uint32_t pin_nums;
19 	void (*irq_config)(void);
20 
21 	DEVICE_MMIO_ROM;
22 };
23 
24 struct gpio_sedi_data {
25 	/* gpio_driver_data needs to be first */
26 	struct gpio_driver_config common;
27 	sys_slist_t callbacks;
28 
29 	DEVICE_MMIO_RAM;
30 };
31 
32 static int gpio_sedi_init(const struct device *dev);
33 
34 #ifdef CONFIG_PM_DEVICE
gpio_sedi_suspend_device(const struct device * dev)35 static int gpio_sedi_suspend_device(const struct device *dev)
36 {
37 	const struct gpio_sedi_config *config = dev->config;
38 	sedi_gpio_t gpio_dev = config->device;
39 	int ret;
40 
41 	if (pm_device_is_busy(dev)) {
42 		return -EBUSY;
43 	}
44 
45 	ret = sedi_gpio_set_power(gpio_dev, SEDI_POWER_SUSPEND);
46 
47 	if (ret != SEDI_DRIVER_OK) {
48 		return -EIO;
49 	}
50 
51 	return 0;
52 }
53 
gpio_sedi_resume_device_from_suspend(const struct device * dev)54 static int gpio_sedi_resume_device_from_suspend(const struct device *dev)
55 {
56 	const struct gpio_sedi_config *config = dev->config;
57 	sedi_gpio_t gpio_dev = config->device;
58 	int ret;
59 
60 	ret = sedi_gpio_set_power(gpio_dev, SEDI_POWER_FULL);
61 	if (ret != SEDI_DRIVER_OK) {
62 		return -EIO;
63 	}
64 
65 	return 0;
66 }
67 
gpio_sedi_pm_action(const struct device * dev,enum pm_device_action action)68 static int gpio_sedi_pm_action(const struct device *dev,
69 			      enum pm_device_action action)
70 {
71 	int ret = 0;
72 
73 	switch (action) {
74 	case PM_DEVICE_ACTION_SUSPEND:
75 		ret = gpio_sedi_suspend_device(dev);
76 		break;
77 	case PM_DEVICE_ACTION_RESUME:
78 		ret = gpio_sedi_resume_device_from_suspend(dev);
79 		break;
80 
81 	default:
82 		ret = -ENOTSUP;
83 	}
84 
85 	return ret;
86 }
87 #endif /* CONFIG_PM_DEVICE */
88 
gpio_sedi_callback(const uint32_t pin_mask,const sedi_gpio_port_t port,void * param)89 static void gpio_sedi_callback(const uint32_t pin_mask,
90 			       const sedi_gpio_port_t port,
91 			       void *param)
92 {
93 	ARG_UNUSED(port);
94 	struct device *dev = (struct device *)param;
95 	struct gpio_sedi_data *data =
96 		(struct gpio_sedi_data *)(dev->data);
97 
98 	/* call the callbacks */
99 	gpio_fire_callbacks(&data->callbacks, dev, pin_mask);
100 }
101 
gpio_sedi_write_raw(const struct device * dev,uint32_t pins,bool is_clear)102 static void gpio_sedi_write_raw(const struct device *dev,
103 				uint32_t pins,
104 				bool is_clear)
105 {
106 	uint8_t i;
107 	const struct gpio_sedi_config *config = dev->config;
108 	sedi_gpio_t gpio_dev = config->device;
109 	sedi_gpio_pin_state_t val;
110 
111 	if (is_clear) {
112 		val = SEDI_GPIO_STATE_LOW;
113 	} else {
114 		val = SEDI_GPIO_STATE_HIGH;
115 	}
116 
117 	for (i = 0; i < config->pin_nums; i++) {
118 		if (pins & 0x1) {
119 			sedi_gpio_write_pin(gpio_dev, i, val);
120 		}
121 		pins >>= 1;
122 		if (pins == 0) {
123 			break;
124 		}
125 	}
126 }
127 
gpio_sedi_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)128 static int gpio_sedi_configure(const struct device *dev, gpio_pin_t pin,
129 			       gpio_flags_t flags)
130 {
131 	const struct gpio_sedi_config *config = dev->config;
132 	sedi_gpio_t gpio_dev = config->device;
133 	sedi_gpio_pin_config_t pin_config = { 0 };
134 
135 	if ((flags & GPIO_OUTPUT) && (flags & GPIO_INPUT)) {
136 		/* Pin cannot be configured as input and output */
137 		return -ENOTSUP;
138 	} else if (!(flags & (GPIO_INPUT | GPIO_OUTPUT))) {
139 		/* Pin has to be configured as input or output */
140 		return -ENOTSUP;
141 	}
142 
143 	pin_config.enable_interrupt = false;
144 	/* Map direction */
145 	if (flags & GPIO_OUTPUT) {
146 		pin_config.direction = SEDI_GPIO_DIR_MODE_OUTPUT;
147 		sedi_gpio_config_pin(gpio_dev, pin, pin_config);
148 		/* Set start state */
149 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
150 			sedi_gpio_write_pin(gpio_dev, pin, 1);
151 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
152 			sedi_gpio_write_pin(gpio_dev, pin, 0);
153 		}
154 	} else {
155 		pin_config.direction = SEDI_GPIO_DIR_MODE_INPUT;
156 		sedi_gpio_config_pin(gpio_dev, pin, pin_config);
157 	}
158 
159 	return 0;
160 }
161 
gpio_sedi_get_raw(const struct device * dev,uint32_t * value)162 static int gpio_sedi_get_raw(const struct device *dev, uint32_t *value)
163 {
164 	const struct gpio_sedi_config *config = dev->config;
165 	sedi_gpio_t gpio_dev = config->device;
166 
167 	*value = sedi_gpio_read_pin_32bits(gpio_dev, 0);
168 
169 	return 0;
170 }
171 
gpio_sedi_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)172 static int gpio_sedi_set_masked_raw(const struct device *dev,
173 				    uint32_t mask,
174 				    uint32_t value)
175 {
176 	gpio_sedi_write_raw(dev, (mask & value), false);
177 
178 	return 0;
179 }
180 
gpio_sedi_set_bits_raw(const struct device * dev,uint32_t pins)181 static int gpio_sedi_set_bits_raw(const struct device *dev, uint32_t pins)
182 {
183 	gpio_sedi_write_raw(dev, pins, false);
184 
185 	return 0;
186 }
187 
gpio_sedi_clear_bits_raw(const struct device * dev,uint32_t pins)188 static int gpio_sedi_clear_bits_raw(const struct device *dev, uint32_t pins)
189 {
190 	gpio_sedi_write_raw(dev, pins, true);
191 
192 	return 0;
193 }
194 
gpio_sedi_toggle_bits(const struct device * dev,uint32_t pins)195 static int gpio_sedi_toggle_bits(const struct device *dev, uint32_t pins)
196 {
197 	const struct gpio_sedi_config *config = dev->config;
198 	sedi_gpio_t gpio_dev = config->device;
199 	uint8_t i;
200 
201 	for (i = 0; i < config->pin_nums; i++) {
202 		if (pins & 0x1) {
203 			sedi_gpio_toggle_pin(gpio_dev, i);
204 		}
205 		pins >>= 1;
206 		if (pins == 0) {
207 			break;
208 		}
209 	}
210 
211 	return 0;
212 }
213 
gpio_sedi_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)214 static int gpio_sedi_interrupt_configure(const struct device *dev,
215 					 gpio_pin_t pin,
216 					 enum gpio_int_mode mode,
217 					 enum gpio_int_trig trig)
218 {
219 	const struct gpio_sedi_config *config = dev->config;
220 	sedi_gpio_t gpio_dev = config->device;
221 	sedi_gpio_pin_config_t pin_config = { 0 };
222 
223 	/* Not support level trigger */
224 	if (mode == GPIO_INT_MODE_LEVEL) {
225 		return -EINVAL;
226 	}
227 	/* Only input needs interrupt enabled */
228 	pin_config.direction = SEDI_GPIO_DIR_MODE_INPUT;
229 	pin_config.enable_wakeup = true;
230 	if (mode == GPIO_INT_MODE_DISABLED) {
231 		pin_config.enable_interrupt = false;
232 	} else {
233 		pin_config.enable_interrupt = true;
234 		switch (trig) {
235 		case GPIO_INT_TRIG_LOW:
236 			pin_config.interrupt_mode =
237 				SEDI_GPIO_INT_MODE_FALLING_EDGE;
238 			break;
239 		case GPIO_INT_TRIG_HIGH:
240 			pin_config.interrupt_mode =
241 				SEDI_GPIO_INT_MODE_RISING_EDGE;
242 			break;
243 		case GPIO_INT_TRIG_BOTH:
244 			pin_config.interrupt_mode =
245 				SEDI_GPIO_INT_MODE_BOTH_EDGE;
246 			break;
247 		}
248 	}
249 	/* Configure interrupt mode */
250 	sedi_gpio_config_pin(gpio_dev, pin, pin_config);
251 
252 	return 0;
253 }
254 
gpio_sedi_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)255 static int gpio_sedi_manage_callback(const struct device *dev,
256 				     struct gpio_callback *callback,
257 				     bool set)
258 {
259 	struct gpio_sedi_data *data = dev->data;
260 
261 	gpio_manage_callback(&(data->callbacks), callback, set);
262 
263 	return 0;
264 }
265 
gpio_sedi_get_pending(const struct device * dev)266 static uint32_t gpio_sedi_get_pending(const struct device *dev)
267 {
268 	const struct gpio_sedi_config *config = dev->config;
269 	sedi_gpio_t gpio_dev = config->device;
270 
271 	return sedi_gpio_get_gisr(gpio_dev, 0);
272 }
273 
274 static const struct gpio_driver_api gpio_sedi_driver_api = {
275 	.pin_configure = gpio_sedi_configure,
276 	.port_get_raw = gpio_sedi_get_raw,
277 	.port_set_masked_raw = gpio_sedi_set_masked_raw,
278 	.port_set_bits_raw = gpio_sedi_set_bits_raw,
279 	.port_clear_bits_raw = gpio_sedi_clear_bits_raw,
280 	.port_toggle_bits = gpio_sedi_toggle_bits,
281 	.pin_interrupt_configure = gpio_sedi_interrupt_configure,
282 	.manage_callback = gpio_sedi_manage_callback,
283 	.get_pending_int = gpio_sedi_get_pending
284 };
285 
286 extern void gpio_isr(IN sedi_gpio_t gpio_device);
287 
gpio_sedi_init(const struct device * dev)288 static int gpio_sedi_init(const struct device *dev)
289 {
290 	int ret;
291 	const struct gpio_sedi_config *config = dev->config;
292 	sedi_gpio_t gpio_dev = config->device;
293 
294 	DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
295 
296 	/* Call sedi gpio init */
297 	ret = sedi_gpio_init(gpio_dev, gpio_sedi_callback, (void *)dev);
298 
299 	if (ret != 0) {
300 		return ret;
301 	}
302 	sedi_gpio_set_power(gpio_dev, SEDI_POWER_FULL);
303 
304 	config->irq_config();
305 
306 	return 0;
307 }
308 
309 #define GPIO_SEDI_IRQ_FLAGS_SENSE0(n) 0
310 #define GPIO_SEDI_IRQ_FLAGS_SENSE1(n) DT_INST_IRQ(n, sense)
311 #define GPIO_SEDI_IRQ_FLAGS(n) \
312 	_CONCAT(GPIO_SEDI_IRQ_FLAGS_SENSE, DT_INST_IRQ_HAS_CELL(n, sense))(n)
313 
314 #define GPIO_DEVICE_INIT_SEDI(n)				       \
315 	static struct gpio_sedi_data gpio##n##_data;	               \
316 	static void gpio_sedi_irq_config_##n(void)		       \
317 	{							       \
318 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \
319 			    gpio_isr, n,			       \
320 			    GPIO_SEDI_IRQ_FLAGS(n));		       \
321 		irq_enable(DT_INST_IRQN(n));			       \
322 	};							       \
323 	static const struct gpio_sedi_config gpio##n##_config = {      \
324 		DEVICE_MMIO_ROM_INIT(DT_DRV_INST(n)),                  \
325 		.common = { 0xFFFFFFFF },			       \
326 		.device = DT_INST_PROP(n, peripheral_id),              \
327 		.pin_nums = DT_INST_PROP(n, ngpios),                   \
328 		.irq_config = gpio_sedi_irq_config_##n,	               \
329 	};							       \
330 	PM_DEVICE_DEFINE(gpio_##n, gpio_sedi_pm_action);               \
331 	DEVICE_DT_INST_DEFINE(n,				       \
332 		      &gpio_sedi_init,				       \
333 		      PM_DEVICE_GET(gpio_##n),		               \
334 		      &gpio##n##_data,			               \
335 		      &gpio##n##_config,			       \
336 		      POST_KERNEL,				       \
337 		      CONFIG_GPIO_INIT_PRIORITY,	               \
338 		      &gpio_sedi_driver_api);
339 
340 DT_INST_FOREACH_STATUS_OKAY(GPIO_DEVICE_INIT_SEDI)
341