1 /*
2 * Copyright (c) 2023 Intel Corporation
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "sedi_driver_pm.h"
8 #include <sedi_gpio_regs.h>
9 #include <sedi_driver_gpio.h>
10
11 /* driver version */
12 #define SEDI_GPIO_DRIVER_VERSION SEDI_DRIVER_VERSION_MAJOR_MINOR(0, 1)
13
14 /* GPIO port pin number */
15 #define GPIO_PORT_PIN_NUM (32U)
16 #define GPIO_PORT_SHIFT_BITS (5U)
17 #define GPIO_PORT_MASK (0x1FU)
18 /* GPIO port access offset unit */
19 #define GPIO_8_BITS_OFFSET (8U)
20 #define GPIO_16_BITS_OFFSET (16U)
21 #define GPIO_32_BITS_OFFSET (32U)
22
23 /* Access the correct register */
24 #define GPIO_SET_BIT(base, reg, index, bit) ((base->reg[index]) |= SET_MASK(bit))
25 #define GPIO_CLEAR_BIT(base, reg, index, bit) ((base->reg[index]) &= CLEAR_MASK(bit))
26
27 #define GPIO_FLAG_INIT (1UL << 0)
28
29 /* GPIO runtime context information */
30 typedef struct {
31 sedi_gpio_event_cb_t cb_event;
32 void *callback_param;
33 uint8_t flag;
34 uint32_t outpin_state[SEDI_GPIO_SOC_PORT_NUM];
35 } gpio_context_t;
36
37 /* resource data structure */
38 typedef struct {
39 sedi_gpio_regs_t *reg;
40 } gpio_resources_t;
41
42 typedef enum {
43 SEDI_GPIO_32BITS_ACCESS,
44 SEDI_GPIO_16BITS_ACCESS,
45 SEDI_GPIO_8BITS_ACCESS
46 } gpio_port_access_t;
47
48 static const uint32_t gpio_port_access_mask[] = { 0xFFFFFFFFU, 0xFFFFU, 0xFFU };
49
50 /* driver version */
51 static const sedi_driver_version_t driver_version = { SEDI_GPIO_API_VERSION,
52 SEDI_GPIO_DRIVER_VERSION };
53
54 /* driver capabilities */
55 static sedi_gpio_capabilities_t driver_capabilities[SEDI_GPIO_NUM] = {
56 {.support_pins_map = 0x3FFFFFFF},
57 };
58
59 /* gpio instance to source mapping*/
60 static gpio_resources_t resources_map[SEDI_GPIO_NUM] = {
61 { .reg = (sedi_gpio_regs_t *)SEDI_IREG_BASE(GPIO, 0) },
62 };
63
64 /* gpio context array */
65 static gpio_context_t gpio_context[SEDI_GPIO_NUM] = { 0 };
66
gpio_set_power(IN sedi_gpio_t gpio_device,IN sedi_power_state_t state)67 static int32_t gpio_set_power(IN sedi_gpio_t gpio_device, IN sedi_power_state_t state)
68 {
69 sedi_devid_t devid = SEDI_DEVID_GPIO0 + gpio_device;
70 int32_t ret = SEDI_DRIVER_OK;
71
72 DBG_CHECK(gpio_device < SEDI_GPIO_NUM, SEDI_DRIVER_ERROR_PARAMETER);
73
74 switch (state) {
75 case SEDI_POWER_FULL:
76 sedi_pm_set_device_power(devid, SEDI_POWER_FULL);
77 break;
78 case SEDI_POWER_LOW:
79 case SEDI_POWER_SUSPEND:
80 case SEDI_POWER_FORCE_SUSPEND:
81 /* Do nothing now, need to use gpio as wake up */
82 break;
83 case SEDI_POWER_OFF:
84 default:
85 ret = SEDI_DRIVER_ERROR_UNSUPPORTED;
86 break;
87 }
88
89 return ret;
90 }
91
gpio_reset_register(IN sedi_gpio_t gpio_device)92 static void gpio_reset_register(IN sedi_gpio_t gpio_device)
93 {
94 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
95 uint8_t i;
96
97 for (i = 0; i < SEDI_GPIO_SOC_PORT_NUM; i++) {
98 reg->gpdr[i] = 0;
99 reg->grer[i] = 0;
100 reg->gfer[i] = 0;
101 reg->gfbr[i] = 0;
102 reg->gimr[i] = 0;
103 /* Clear all status bits */
104 reg->gisr[i] = 0xFFFFFFFF;
105 reg->gwmr[i] = 0;
106 /* Clear all status bits */
107 reg->gwsr[i] = 0xFFFFFFFF;
108 }
109 }
110
gpio_write_pin_port(IN sedi_gpio_t gpio_device,IN gpio_port_access_t access_type,IN uint8_t group,IN sedi_gpio_pin_state_t state)111 static void gpio_write_pin_port(IN sedi_gpio_t gpio_device, IN gpio_port_access_t access_type,
112 IN uint8_t group, IN sedi_gpio_pin_state_t state)
113 {
114 uint8_t port = (group >> access_type);
115 uint8_t offset_unit, offset;
116 uint32_t pin_bit;
117 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
118 gpio_context_t *context = &(gpio_context[gpio_device]);
119
120 if (access_type == SEDI_GPIO_8BITS_ACCESS) {
121 offset_unit = GPIO_8_BITS_OFFSET;
122 } else if (access_type == SEDI_GPIO_16BITS_ACCESS) {
123 offset_unit = GPIO_16_BITS_OFFSET;
124 } else {
125 offset_unit = GPIO_32_BITS_OFFSET;
126 }
127
128 offset = (group & (uint32_t)((1U << access_type) - 1U)) * offset_unit;
129 pin_bit = (gpio_port_access_mask[access_type] << offset);
130
131 if (state == SEDI_GPIO_STATE_HIGH) {
132 reg->gpsr[port] = pin_bit;
133 context->outpin_state[port] |= pin_bit;
134 } else {
135 reg->gpcr[port] = pin_bit;
136 context->outpin_state[port] &= (~pin_bit);
137 }
138 }
139
gpio_read_pin_port(IN sedi_gpio_t gpio_device,IN gpio_port_access_t access_type,IN uint8_t group)140 static uint32_t gpio_read_pin_port(IN sedi_gpio_t gpio_device, IN gpio_port_access_t access_type,
141 IN uint8_t group)
142 {
143 uint8_t port = (group >> access_type);
144 uint8_t offset_unit, offset;
145 uint32_t pin_bit;
146 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
147 sedi_gpio_capabilities_t cap;
148
149 /* The port return value will mask the pin maps */
150 sedi_gpio_get_capabilities(gpio_device, &cap);
151 if (access_type == SEDI_GPIO_8BITS_ACCESS) {
152 offset_unit = GPIO_8_BITS_OFFSET;
153 } else if (access_type == SEDI_GPIO_16BITS_ACCESS) {
154 offset_unit = GPIO_16_BITS_OFFSET;
155 } else {
156 offset_unit = GPIO_32_BITS_OFFSET;
157 }
158
159 offset = (group & (uint32_t)((1U << access_type) - 1U)) * offset_unit;
160 pin_bit = (gpio_port_access_mask[access_type] << offset);
161
162 return (((reg->gplr[port] & pin_bit) >> offset) & cap.support_pins_map);
163 }
164
gpio_isr(IN sedi_gpio_t gpio_device)165 void gpio_isr(IN sedi_gpio_t gpio_device)
166 {
167 sedi_gpio_regs_t *gpio = resources_map[gpio_device].reg;
168 gpio_context_t *context = &(gpio_context[gpio_device]);
169 uint8_t i;
170 uint32_t gisr;
171 uint32_t gimr;
172
173 for (i = 0; i < SEDI_GPIO_SOC_PORT_NUM; i++) {
174 gisr = gpio->gisr[i];
175 gimr = gpio->gimr[i];
176
177 gisr &= gimr;
178
179 /* Clear the interrupts */
180 gpio->gisr[i] = gisr;
181
182 if ((context->cb_event) && (gisr != 0)) {
183 (context->cb_event)(gisr, i, context->callback_param);
184 }
185 }
186 }
187
sedi_gpio_get_version(void)188 sedi_driver_version_t sedi_gpio_get_version(void)
189 {
190 return driver_version;
191 }
192
sedi_gpio_get_capabilities(IN sedi_gpio_t gpio_device,OUT sedi_gpio_capabilities_t * cap)193 int32_t sedi_gpio_get_capabilities(IN sedi_gpio_t gpio_device, OUT sedi_gpio_capabilities_t *cap)
194 {
195 DBG_CHECK(gpio_device < SEDI_GPIO_NUM, SEDI_DRIVER_ERROR_PARAMETER);
196
197 if (sedi_dev_is_self_owned(SEDI_DEVID_GPIO0 + gpio_device)) {
198 driver_capabilities[gpio_device].is_available = 1;
199 } else {
200 driver_capabilities[gpio_device].is_available = 0;
201 }
202
203 *cap = driver_capabilities[gpio_device];
204
205 return SEDI_DRIVER_OK;
206 }
207
sedi_gpio_init(IN sedi_gpio_t gpio_device,IN sedi_gpio_event_cb_t cb,INOUT void * param)208 int32_t sedi_gpio_init(IN sedi_gpio_t gpio_device, IN sedi_gpio_event_cb_t cb, INOUT void *param)
209 {
210 DBG_CHECK(gpio_device < SEDI_GPIO_NUM, SEDI_DRIVER_ERROR_PARAMETER);
211
212 if (!sedi_dev_is_self_owned(SEDI_DEVID_GPIO0 + gpio_device)) {
213 return SEDI_DRIVER_ERROR_NO_DEV;
214 }
215
216 if (gpio_context[gpio_device].flag == GPIO_FLAG_INIT)
217 return SEDI_DRIVER_ERROR_BUSY;
218
219 /* Set all registers to default state */
220 gpio_reset_register(gpio_device);
221
222 /* Register callback for GPIO */
223 gpio_context[gpio_device].cb_event = cb;
224 gpio_context[gpio_device].callback_param = param;
225
226 /* Set flag to init */
227 gpio_context[gpio_device].flag = GPIO_FLAG_INIT;
228
229 return SEDI_DRIVER_OK;
230 }
231
sedi_gpio_uninit(IN sedi_gpio_t gpio_device)232 int32_t sedi_gpio_uninit(IN sedi_gpio_t gpio_device)
233 {
234 DBG_CHECK(gpio_device < SEDI_GPIO_NUM, SEDI_DRIVER_ERROR_PARAMETER);
235
236 gpio_context_t *context = &(gpio_context[gpio_device]);
237 uint8_t i;
238
239 /* Clear the internal context */
240 context->cb_event = NULL;
241 context->callback_param = NULL;
242 context->flag = 0;
243 for (i = 0; i < SEDI_GPIO_SOC_PORT_NUM; i++) {
244 context->outpin_state[i] = 0;
245 }
246
247 /* Set all registers to default state */
248 gpio_reset_register(gpio_device);
249
250 return SEDI_DRIVER_OK;
251 }
252
sedi_gpio_set_power(IN sedi_gpio_t gpio_device,IN sedi_power_state_t state)253 int32_t sedi_gpio_set_power(IN sedi_gpio_t gpio_device, IN sedi_power_state_t state)
254 {
255 DBG_CHECK(gpio_device < SEDI_GPIO_NUM, SEDI_DRIVER_ERROR_PARAMETER);
256
257 return gpio_set_power(gpio_device, state);
258 }
259
sedi_gpio_config_pin(IN sedi_gpio_t gpio_device,IN uint32_t pin,IN sedi_gpio_pin_config_t pin_config)260 void sedi_gpio_config_pin(IN sedi_gpio_t gpio_device, IN uint32_t pin,
261 IN sedi_gpio_pin_config_t pin_config)
262 {
263 sedi_gpio_regs_t *base = resources_map[gpio_device].reg;
264 uint8_t port = pin >> GPIO_PORT_SHIFT_BITS;
265 uint8_t offset = pin & GPIO_PORT_MASK;
266
267 if (pin_config.direction == SEDI_GPIO_DIR_MODE_OUTPUT) {
268 GPIO_SET_BIT(base, gpdr, port, offset);
269 } else {
270 GPIO_CLEAR_BIT(base, gpdr, port, offset);
271
272 /* Clear the interrupt mode first */
273 GPIO_CLEAR_BIT(base, gfer, port, offset);
274 GPIO_CLEAR_BIT(base, grer, port, offset);
275
276 if (pin_config.interrupt_mode & SEDI_GPIO_INT_MODE_FALLING_EDGE) {
277 GPIO_SET_BIT(base, gfer, port, offset);
278 }
279
280 if (pin_config.interrupt_mode & SEDI_GPIO_INT_MODE_RISING_EDGE) {
281 GPIO_SET_BIT(base, grer, port, offset);
282 }
283
284 if (pin_config.enable_interrupt) {
285 GPIO_SET_BIT(base, gimr, port, offset);
286 } else {
287 GPIO_CLEAR_BIT(base, gimr, port, offset);
288 }
289
290 if (pin_config.enable_wakeup) {
291 GPIO_SET_BIT(base, gwmr, port, offset);
292 } else {
293 GPIO_CLEAR_BIT(base, gwmr, port, offset);
294 }
295 }
296 }
297
sedi_gpio_write_pin(IN sedi_gpio_t gpio_device,IN uint32_t pin,IN sedi_gpio_pin_state_t pin_state)298 void sedi_gpio_write_pin(IN sedi_gpio_t gpio_device, IN uint32_t pin,
299 IN sedi_gpio_pin_state_t pin_state)
300 {
301 uint8_t port = pin >> GPIO_PORT_SHIFT_BITS;
302 uint8_t offset = pin & GPIO_PORT_MASK;
303 uint32_t pin_bit = SET_MASK(offset);
304 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
305 gpio_context_t *context = &(gpio_context[gpio_device]);
306
307 if (pin_state == SEDI_GPIO_STATE_HIGH) {
308 reg->gpsr[port] = pin_bit;
309 context->outpin_state[port] |= pin_bit;
310 } else {
311 reg->gpcr[port] = pin_bit;
312 context->outpin_state[port] &= (~pin_bit);
313 }
314 }
315
sedi_gpio_write_pin_8bits(IN sedi_gpio_t gpio_device,IN uint8_t group,IN sedi_gpio_pin_state_t pin_state)316 void sedi_gpio_write_pin_8bits(IN sedi_gpio_t gpio_device, IN uint8_t group,
317 IN sedi_gpio_pin_state_t pin_state)
318 {
319 gpio_write_pin_port(gpio_device, SEDI_GPIO_8BITS_ACCESS, group, pin_state);
320 }
321
sedi_gpio_write_pin_16bits(IN sedi_gpio_t gpio_device,IN uint8_t group,IN sedi_gpio_pin_state_t pin_state)322 void sedi_gpio_write_pin_16bits(IN sedi_gpio_t gpio_device, IN uint8_t group,
323 IN sedi_gpio_pin_state_t pin_state)
324 {
325 gpio_write_pin_port(gpio_device, SEDI_GPIO_16BITS_ACCESS, group, pin_state);
326 }
327
sedi_gpio_write_pin_32bits(IN sedi_gpio_t gpio_device,IN uint8_t group,IN sedi_gpio_pin_state_t pin_state)328 void sedi_gpio_write_pin_32bits(IN sedi_gpio_t gpio_device, IN uint8_t group,
329 IN sedi_gpio_pin_state_t pin_state)
330 {
331 gpio_write_pin_port(gpio_device, SEDI_GPIO_32BITS_ACCESS, group, pin_state);
332 }
333
sedi_gpio_read_pin(IN sedi_gpio_t gpio_device,IN uint32_t pin)334 sedi_gpio_pin_state_t sedi_gpio_read_pin(IN sedi_gpio_t gpio_device, IN uint32_t pin)
335 {
336 uint8_t port = pin >> GPIO_PORT_SHIFT_BITS;
337 uint8_t offset = pin & GPIO_PORT_MASK;
338 uint32_t pin_bit = SET_MASK(offset);
339 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
340
341 uint32_t pin_val = ((pin_bit & reg->gplr[port]) == pin_bit);
342
343 return pin_val ? SEDI_GPIO_STATE_HIGH : SEDI_GPIO_STATE_LOW;
344 }
345
sedi_gpio_read_pin_8bits(IN sedi_gpio_t gpio_device,IN uint8_t group)346 uint8_t sedi_gpio_read_pin_8bits(IN sedi_gpio_t gpio_device, IN uint8_t group)
347 {
348 return gpio_read_pin_port(gpio_device, SEDI_GPIO_8BITS_ACCESS, group);
349 }
350
sedi_gpio_read_pin_16bits(IN sedi_gpio_t gpio_device,IN uint8_t group)351 uint16_t sedi_gpio_read_pin_16bits(IN sedi_gpio_t gpio_device, IN uint8_t group)
352 {
353 return gpio_read_pin_port(gpio_device, SEDI_GPIO_16BITS_ACCESS, group);
354 }
355
sedi_gpio_read_pin_32bits(IN sedi_gpio_t gpio_device,IN uint8_t group)356 uint32_t sedi_gpio_read_pin_32bits(IN sedi_gpio_t gpio_device, IN uint8_t group)
357 {
358 return gpio_read_pin_port(gpio_device, SEDI_GPIO_32BITS_ACCESS, group);
359 }
360
sedi_gpio_toggle_pin(IN sedi_gpio_t gpio_device,IN uint32_t pin)361 void sedi_gpio_toggle_pin(IN sedi_gpio_t gpio_device, IN uint32_t pin)
362 {
363 uint8_t port = pin >> GPIO_PORT_SHIFT_BITS;
364 uint8_t offset = pin & GPIO_PORT_MASK;
365 uint32_t pin_bit = SET_MASK(offset);
366 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
367 gpio_context_t *context = &(gpio_context[gpio_device]);
368
369 if (context->outpin_state[port] & pin_bit) {
370 reg->gpcr[port] = pin_bit;
371 context->outpin_state[port] &= ~pin_bit;
372 } else {
373 reg->gpsr[port] = pin_bit;
374 context->outpin_state[port] |= pin_bit;
375 }
376 }
377
sedi_gpio_get_gisr(IN sedi_gpio_t gpio_device,IN sedi_gpio_port_t port)378 uint32_t sedi_gpio_get_gisr(IN sedi_gpio_t gpio_device, IN sedi_gpio_port_t port)
379 {
380 SEDI_ASSERT(gpio_device < SEDI_GPIO_NUM);
381 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
382
383 return reg->gisr[port];
384 }
385
sedi_gpio_get_gwsr(IN sedi_gpio_t gpio_device,IN sedi_gpio_port_t port)386 uint32_t sedi_gpio_get_gwsr(IN sedi_gpio_t gpio_device, IN sedi_gpio_port_t port)
387 {
388 SEDI_ASSERT(gpio_device < SEDI_GPIO_NUM);
389 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
390
391 return reg->gwsr[port];
392 }
393
sedi_gpio_clear_gisr(IN sedi_gpio_t gpio_device,IN sedi_gpio_port_t port,IN uint32_t val)394 void sedi_gpio_clear_gisr(IN sedi_gpio_t gpio_device, IN sedi_gpio_port_t port, IN uint32_t val)
395 {
396 SEDI_ASSERT(gpio_device < SEDI_GPIO_NUM);
397 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
398
399 /* The register is w1c */
400 reg->gisr[port] = val;
401 }
402
sedi_gpio_clear_gwsr(IN sedi_gpio_t gpio_device,IN sedi_gpio_port_t port,IN uint32_t val)403 void sedi_gpio_clear_gwsr(IN sedi_gpio_t gpio_device, IN sedi_gpio_port_t port, IN uint32_t val)
404 {
405 SEDI_ASSERT(gpio_device < SEDI_GPIO_NUM);
406 sedi_gpio_regs_t *reg = resources_map[gpio_device].reg;
407
408 /* The register is w1c */
409 reg->gwsr[port] = val;
410 }
411
sedi_gpio_enable_interrupt(IN sedi_gpio_t gpio_device,IN uint32_t pin,bool enable)412 void sedi_gpio_enable_interrupt(IN sedi_gpio_t gpio_device, IN uint32_t pin, bool enable)
413 {
414 SEDI_ASSERT(gpio_device < SEDI_GPIO_NUM);
415 sedi_gpio_regs_t *base = resources_map[gpio_device].reg;
416 uint8_t port = pin >> GPIO_PORT_SHIFT_BITS;
417 uint8_t offset = pin & GPIO_PORT_MASK;
418
419 if (enable) {
420 GPIO_SET_BIT(base, gimr, port, offset);
421 } else {
422 GPIO_CLEAR_BIT(base, gimr, port, offset);
423 }
424 }
425
sedi_gpio_enable_wakeup(IN sedi_gpio_t gpio_device,IN uint32_t pin,bool enable)426 void sedi_gpio_enable_wakeup(IN sedi_gpio_t gpio_device, IN uint32_t pin, bool enable)
427 {
428 SEDI_ASSERT(gpio_device < SEDI_GPIO_NUM);
429 sedi_gpio_regs_t *base = resources_map[gpio_device].reg;
430 uint8_t port = pin >> GPIO_PORT_SHIFT_BITS;
431 uint8_t offset = pin & GPIO_PORT_MASK;
432
433 if (enable) {
434 GPIO_SET_BIT(base, gwmr, port, offset);
435 } else {
436 GPIO_CLEAR_BIT(base, gwmr, port, offset);
437 }
438 }
439