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