1 /*
2 * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon company) or
3 * an affiliate of Cypress Semiconductor Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /**
9 * @brief GPIO driver for Infineon CAT1 MCU family.
10 *
11 * Note:
12 * - Trigger detection on pin rising or falling edge (GPIO_INT_TRIG_BOTH)
13 * is not supported in current version of GPIO CAT1 driver.
14 */
15
16 #define DT_DRV_COMPAT infineon_cat1_gpio
17
18 #include <zephyr/drivers/gpio.h>
19 #include <zephyr/drivers/gpio/gpio_utils.h>
20 #include <zephyr/irq.h>
21
22 #include <cy_gpio.h>
23
24 #include <zephyr/logging/log.h>
25 LOG_MODULE_REGISTER(gpio_cat1, CONFIG_GPIO_LOG_LEVEL);
26
27 /* Device config structure */
28 struct gpio_cat1_config {
29 /* gpio_driver_config needs to be first */
30 struct gpio_driver_config common;
31 GPIO_PRT_Type *regs;
32 uint8_t ngpios;
33 uint8_t intr_priority;
34 };
35
36 /* Data structure */
37 struct gpio_cat1_data {
38 /* gpio_driver_data needs to be first */
39 struct gpio_driver_data common;
40
41 /* device's owner of this data */
42 const struct device *dev;
43
44 /* callbacks list */
45 sys_slist_t callbacks;
46 };
47
gpio_cat1_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)48 static int gpio_cat1_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
49 {
50 uint32_t drive_mode = CY_GPIO_DM_HIGHZ;
51 bool pin_val = false;
52 const struct gpio_cat1_config *const cfg = dev->config;
53 GPIO_PRT_Type *const base = cfg->regs;
54
55 switch (flags & (GPIO_INPUT | GPIO_OUTPUT | GPIO_DISCONNECTED)) {
56 case GPIO_INPUT:
57 if ((flags & GPIO_PULL_UP) && (flags & GPIO_PULL_DOWN)) {
58 drive_mode = CY_GPIO_DM_PULLUP_DOWN;
59 } else if (flags & GPIO_PULL_UP) {
60 drive_mode = CY_GPIO_DM_PULLUP;
61 pin_val = true;
62 } else if (flags & GPIO_PULL_DOWN) {
63 drive_mode = CY_GPIO_DM_PULLDOWN;
64 } else {
65 drive_mode = CY_GPIO_DM_HIGHZ;
66 }
67 break;
68
69 case GPIO_OUTPUT:
70 if (flags & GPIO_SINGLE_ENDED) {
71 if (flags & GPIO_LINE_OPEN_DRAIN) {
72 drive_mode = CY_GPIO_DM_OD_DRIVESLOW;
73 pin_val = true;
74 } else {
75 drive_mode = CY_GPIO_DM_OD_DRIVESHIGH;
76 pin_val = false;
77 }
78 } else {
79 drive_mode = CY_GPIO_DM_STRONG;
80 pin_val = (flags & GPIO_OUTPUT_INIT_HIGH) ? true : false;
81 }
82 break;
83
84 case GPIO_DISCONNECTED:
85 Cy_GPIO_SetInterruptMask(base, pin, 0);
86 drive_mode = CY_GPIO_DM_ANALOG;
87 pin_val = false;
88 break;
89
90 default:
91 return -ENOTSUP;
92 }
93
94 Cy_GPIO_Pin_FastInit(base, pin, drive_mode, pin_val, HSIOM_SEL_GPIO);
95
96 return 0;
97 }
98
gpio_cat1_port_get_raw(const struct device * dev,uint32_t * value)99 static int gpio_cat1_port_get_raw(const struct device *dev,
100 uint32_t *value)
101 {
102 const struct gpio_cat1_config *const cfg = dev->config;
103 GPIO_PRT_Type *const base = cfg->regs;
104
105 *value = GPIO_PRT_IN(base);
106
107 return 0;
108 }
109
gpio_cat1_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)110 static int gpio_cat1_port_set_masked_raw(const struct device *dev,
111 uint32_t mask, uint32_t value)
112 {
113 const struct gpio_cat1_config *const cfg = dev->config;
114 GPIO_PRT_Type *const base = cfg->regs;
115
116 GPIO_PRT_OUT(base) = (GPIO_PRT_OUT(base) & ~mask) | (mask & value);
117
118 return 0;
119 }
120
gpio_cat1_port_set_bits_raw(const struct device * dev,uint32_t mask)121 static int gpio_cat1_port_set_bits_raw(const struct device *dev,
122 uint32_t mask)
123 {
124 const struct gpio_cat1_config *const cfg = dev->config;
125 GPIO_PRT_Type *const base = cfg->regs;
126
127 GPIO_PRT_OUT_SET(base) = mask;
128
129 return 0;
130 }
131
gpio_cat1_port_clear_bits_raw(const struct device * dev,uint32_t mask)132 static int gpio_cat1_port_clear_bits_raw(const struct device *dev,
133 uint32_t mask)
134 {
135 const struct gpio_cat1_config *const cfg = dev->config;
136 GPIO_PRT_Type *const base = cfg->regs;
137
138 GPIO_PRT_OUT_CLR(base) = mask;
139
140 return 0;
141 }
142
gpio_cat1_port_toggle_bits(const struct device * dev,uint32_t mask)143 static int gpio_cat1_port_toggle_bits(const struct device *dev,
144 uint32_t mask)
145 {
146 const struct gpio_cat1_config *const cfg = dev->config;
147 GPIO_PRT_Type *const base = cfg->regs;
148
149 GPIO_PRT_OUT_INV(base) = mask;
150
151 return 0;
152 }
153
gpio_cat1_get_pending_int(const struct device * dev)154 static uint32_t gpio_cat1_get_pending_int(const struct device *dev)
155 {
156 const struct gpio_cat1_config *const cfg = dev->config;
157 GPIO_PRT_Type *const base = cfg->regs;
158
159 return GPIO_PRT_INTR_MASKED(base);
160 }
161
gpio_isr_handler(const struct device * dev)162 static void gpio_isr_handler(const struct device *dev)
163 {
164 const struct gpio_cat1_config *const cfg = dev->config;
165 GPIO_PRT_Type *const base = cfg->regs;
166 uint32_t pins = GPIO_PRT_INTR_MASKED(base);
167
168 for (uint8_t i = 0; i < CY_GPIO_PINS_MAX; i++) {
169 Cy_GPIO_ClearInterrupt(base, i);
170 }
171
172 if (dev) {
173 gpio_fire_callbacks(&((struct gpio_cat1_data *const)(dev)->data)->callbacks, dev,
174 pins);
175 }
176
177
178 }
179
gpio_cat1_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)180 static int gpio_cat1_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
181 enum gpio_int_mode mode, enum gpio_int_trig trig)
182 {
183 uint32_t trig_pdl = CY_GPIO_INTR_DISABLE;
184 const struct gpio_cat1_config *const cfg = dev->config;
185 GPIO_PRT_Type *const base = cfg->regs;
186
187 /* Level interrupts (GPIO_INT_MODE_LEVEL) is not supported */
188 if (mode == GPIO_INT_MODE_LEVEL) {
189 return -ENOTSUP;
190 }
191
192 switch (trig) {
193 case GPIO_INT_TRIG_LOW:
194 trig_pdl = CY_GPIO_INTR_FALLING;
195 break;
196
197 case GPIO_INT_TRIG_HIGH:
198 trig_pdl = CY_GPIO_INTR_RISING;
199 break;
200
201 case GPIO_INT_TRIG_BOTH:
202 trig_pdl = CY_GPIO_INTR_BOTH;
203 break;
204
205 default:
206 return -ENOTSUP;
207 }
208
209 Cy_GPIO_SetInterruptEdge(base, pin, trig_pdl);
210 Cy_GPIO_SetInterruptMask(base, pin,
211 (uint32_t)(mode == GPIO_INT_MODE_DISABLED) ? false : true);
212
213 return 0;
214 }
215
gpio_cat1_manage_callback(const struct device * port,struct gpio_callback * callback,bool set)216 static int gpio_cat1_manage_callback(const struct device *port,
217 struct gpio_callback *callback,
218 bool set)
219 {
220 return gpio_manage_callback(&((struct gpio_cat1_data *const)(port)->data)->callbacks,
221 callback, set);
222 }
223
224 static DEVICE_API(gpio, gpio_cat1_api) = {
225 .pin_configure = gpio_cat1_configure,
226 .port_get_raw = gpio_cat1_port_get_raw,
227 .port_set_masked_raw = gpio_cat1_port_set_masked_raw,
228 .port_set_bits_raw = gpio_cat1_port_set_bits_raw,
229 .port_clear_bits_raw = gpio_cat1_port_clear_bits_raw,
230 .port_toggle_bits = gpio_cat1_port_toggle_bits,
231 .pin_interrupt_configure = gpio_cat1_pin_interrupt_configure,
232 .manage_callback = gpio_cat1_manage_callback,
233 .get_pending_int = gpio_cat1_get_pending_int,
234 };
235
236 #define GPIO_CAT1_INIT_FUNC(n) \
237 static int gpio_cat1##n##_init(const struct device *dev) \
238 { \
239 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_isr_handler, \
240 DEVICE_DT_INST_GET(n), 0); \
241 irq_enable(DT_INST_IRQN(n)); \
242 \
243 return 0; \
244 }
245
246 #define GPIO_CAT1_INIT(n) \
247 \
248 static const struct gpio_cat1_config _cat1_gpio##n##_config = { \
249 .common = \
250 { \
251 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
252 }, \
253 .intr_priority = DT_INST_IRQ_BY_IDX(n, 0, priority), \
254 .ngpios = DT_INST_PROP(n, ngpios), \
255 .regs = (GPIO_PRT_Type *)DT_INST_REG_ADDR(n), \
256 }; \
257 \
258 static struct gpio_cat1_data _cat1_gpio##n##_data; \
259 \
260 GPIO_CAT1_INIT_FUNC(n) \
261 \
262 DEVICE_DT_INST_DEFINE(n, gpio_cat1##n##_init, NULL, &_cat1_gpio##n##_data, \
263 &_cat1_gpio##n##_config, POST_KERNEL, \
264 CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &gpio_cat1_api);
265
266 DT_INST_FOREACH_STATUS_OKAY(GPIO_CAT1_INIT)
267