1 /*
2 * Copyright (c) 2023-2024 Analog Devices, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/drivers/clock_control.h>
8 #include <zephyr/drivers/gpio/gpio_utils.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/logging/log.h>
11 #include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
12 #include <zephyr/dt-bindings/gpio/adi-max32-gpio.h>
13 #include <gpio.h>
14
15 #define DT_DRV_COMPAT adi_max32_gpio
16
17 LOG_MODULE_REGISTER(gpio_max32, CONFIG_GPIO_LOG_LEVEL);
18
19 struct max32_gpio_config {
20 struct gpio_driver_config common;
21 mxc_gpio_regs_t *regs;
22 const struct device *clock;
23 void (*irq_func)(void);
24 struct max32_perclk perclk;
25 };
26
27 struct max32_gpio_data {
28 struct gpio_driver_data common;
29 sys_slist_t cb_list;
30 };
31
api_port_get_raw(const struct device * dev,uint32_t * value)32 static int api_port_get_raw(const struct device *dev, uint32_t *value)
33 {
34 const struct max32_gpio_config *cfg = dev->config;
35
36 *value = MXC_GPIO_InGet(cfg->regs, (unsigned int)-1);
37 return 0;
38 }
39
api_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)40 static int api_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask,
41 gpio_port_value_t value)
42 {
43 const struct max32_gpio_config *cfg = dev->config;
44
45 MXC_GPIO_OutPut(cfg->regs, mask, value);
46 return 0;
47 }
48
api_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)49 static int api_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins)
50 {
51 const struct max32_gpio_config *cfg = dev->config;
52
53 MXC_GPIO_OutSet(cfg->regs, pins);
54 return 0;
55 }
56
api_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)57 static int api_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins)
58 {
59 const struct max32_gpio_config *cfg = dev->config;
60
61 MXC_GPIO_OutClr(cfg->regs, pins);
62 return 0;
63 }
64
api_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)65 static int api_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
66 {
67 const struct max32_gpio_config *cfg = dev->config;
68
69 MXC_GPIO_OutToggle(cfg->regs, pins);
70 return 0;
71 }
72
api_pin_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)73 static int api_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
74 {
75 const struct max32_gpio_config *cfg = dev->config;
76 mxc_gpio_cfg_t gpio_cfg;
77 int ret;
78
79 /* MAX32xxx MCUs does not support SINGLE_ENDED, open drain, mode */
80 if (flags & GPIO_SINGLE_ENDED) {
81 return -ENOTSUP;
82 }
83
84 gpio_cfg.port = cfg->regs;
85 gpio_cfg.mask = BIT(pin);
86
87 if (flags & GPIO_PULL_UP) {
88 gpio_cfg.pad = MXC_GPIO_PAD_PULL_UP;
89 } else if (flags & GPIO_PULL_DOWN) {
90 gpio_cfg.pad = MXC_GPIO_PAD_PULL_DOWN;
91 } else if (flags & MAX32_GPIO_WEAK_PULL_UP) {
92 gpio_cfg.pad = MXC_GPIO_PAD_WEAK_PULL_UP;
93 } else if (flags & MAX32_GPIO_WEAK_PULL_DOWN) {
94 gpio_cfg.pad = MXC_GPIO_PAD_WEAK_PULL_DOWN;
95 } else {
96 gpio_cfg.pad = MXC_GPIO_PAD_NONE;
97 }
98
99 if (flags & GPIO_OUTPUT) {
100 gpio_cfg.func = MXC_GPIO_FUNC_OUT;
101 } else if (flags & GPIO_INPUT) {
102 gpio_cfg.func = MXC_GPIO_FUNC_IN;
103 } else {
104 gpio_cfg.func = MXC_GPIO_FUNC_IN;
105 gpio_cfg.pad = MXC_GPIO_PAD_NONE;
106 }
107
108 if (flags & MAX32_GPIO_VSEL_VDDIOH) {
109 gpio_cfg.vssel = MXC_GPIO_VSSEL_VDDIOH;
110 } else {
111 gpio_cfg.vssel = MXC_GPIO_VSSEL_VDDIO;
112 }
113
114 switch (flags & MAX32_GPIO_DRV_STRENGTH_MASK) {
115 case MAX32_GPIO_DRV_STRENGTH_1:
116 gpio_cfg.drvstr = MXC_GPIO_DRVSTR_1;
117 break;
118 case MAX32_GPIO_DRV_STRENGTH_2:
119 gpio_cfg.drvstr = MXC_GPIO_DRVSTR_2;
120 break;
121 case MAX32_GPIO_DRV_STRENGTH_3:
122 gpio_cfg.drvstr = MXC_GPIO_DRVSTR_3;
123 break;
124 default:
125 gpio_cfg.drvstr = MXC_GPIO_DRVSTR_0;
126 break;
127 }
128
129 ret = MXC_GPIO_Config(&gpio_cfg);
130 if (ret != 0) {
131 return -ENOTSUP;
132 }
133
134 if (flags & GPIO_OUTPUT) {
135 if (flags & GPIO_OUTPUT_INIT_LOW) {
136 MXC_GPIO_OutClr(cfg->regs, BIT(pin));
137 } else if (flags & GPIO_OUTPUT_INIT_HIGH) {
138 MXC_GPIO_OutSet(cfg->regs, BIT(pin));
139 }
140 }
141
142 return 0;
143 }
144
api_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)145 static int api_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
146 enum gpio_int_mode mode, enum gpio_int_trig trig)
147 {
148 const struct max32_gpio_config *cfg = dev->config;
149 mxc_gpio_cfg_t gpio_cfg;
150
151 gpio_cfg.port = cfg->regs;
152 gpio_cfg.mask = BIT(pin);
153 /* rest of the parameters not necessary */
154
155 if (mode == GPIO_INT_MODE_DISABLED) {
156 MXC_GPIO_DisableInt(cfg->regs, gpio_cfg.mask);
157
158 /* clear interrupt flags */
159 MXC_GPIO_ClearFlags(cfg->regs, (MXC_GPIO_GetFlags(cfg->regs) & gpio_cfg.mask));
160
161 return 0;
162 }
163
164 switch (mode) {
165 case GPIO_INT_MODE_LEVEL:
166 if (trig == GPIO_INT_TRIG_LOW) {
167 MXC_GPIO_IntConfig(&gpio_cfg, MXC_GPIO_INT_LOW);
168 } else if (trig == GPIO_INT_TRIG_HIGH) {
169 MXC_GPIO_IntConfig(&gpio_cfg, MXC_GPIO_INT_HIGH);
170 } else if (trig == GPIO_INT_TRIG_BOTH) {
171 MXC_GPIO_IntConfig(&gpio_cfg, MXC_GPIO_INT_BOTH);
172 } else {
173 return -EINVAL;
174 }
175 break;
176 case GPIO_INT_MODE_EDGE:
177 if (trig == GPIO_INT_TRIG_LOW) {
178 MXC_GPIO_IntConfig(&gpio_cfg, MXC_GPIO_INT_FALLING);
179 } else if (trig == GPIO_INT_TRIG_HIGH) {
180 MXC_GPIO_IntConfig(&gpio_cfg, MXC_GPIO_INT_RISING);
181 } else if (trig == GPIO_INT_TRIG_BOTH) {
182 MXC_GPIO_IntConfig(&gpio_cfg, MXC_GPIO_INT_BOTH);
183 } else {
184 return -EINVAL;
185 }
186 break;
187 default:
188 return -EINVAL;
189 }
190
191 cfg->irq_func();
192 MXC_GPIO_EnableInt(cfg->regs, gpio_cfg.mask);
193
194 return 0;
195 }
196
api_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)197 static int api_manage_callback(const struct device *dev, struct gpio_callback *callback, bool set)
198 {
199 struct max32_gpio_data *data = dev->data;
200
201 return gpio_manage_callback(&(data->cb_list), callback, set);
202 }
203
204 static DEVICE_API(gpio, gpio_max32_driver) = {
205 .pin_configure = api_pin_configure,
206 .port_get_raw = api_port_get_raw,
207 .port_set_masked_raw = api_port_set_masked_raw,
208 .port_set_bits_raw = api_port_set_bits_raw,
209 .port_clear_bits_raw = api_port_clear_bits_raw,
210 .port_toggle_bits = api_port_toggle_bits,
211 .pin_interrupt_configure = api_pin_interrupt_configure,
212 .manage_callback = api_manage_callback,
213 };
214
gpio_max32_isr(const void * param)215 static void gpio_max32_isr(const void *param)
216 {
217 const struct device *dev = param;
218 const struct max32_gpio_config *cfg = dev->config;
219 struct max32_gpio_data *data = dev->data;
220
221 unsigned int flags = MXC_GPIO_GetFlags(cfg->regs);
222 /* clear interrupt flags */
223 MXC_GPIO_ClearFlags(cfg->regs, flags);
224
225 gpio_fire_callbacks(&(data->cb_list), dev, flags);
226 }
227
gpio_max32_init(const struct device * dev)228 static int gpio_max32_init(const struct device *dev)
229 {
230 int ret = 0;
231 const struct max32_gpio_config *cfg = dev->config;
232
233 if (cfg->clock != NULL) {
234 /* enable clock */
235 ret = clock_control_on(cfg->clock, (clock_control_subsys_t)&cfg->perclk);
236 if (ret != 0) {
237 LOG_ERR("cannot enable GPIO clock");
238 return ret;
239 }
240 }
241
242 return ret;
243 }
244
245 #define MAX32_GPIO_INIT(_num) \
246 static void gpio_max32_irq_init_##_num(void) \
247 { \
248 IRQ_CONNECT(DT_INST_IRQN(_num), DT_INST_IRQ(_num, priority), gpio_max32_isr, \
249 DEVICE_DT_INST_GET(_num), 0); \
250 irq_enable(DT_INST_IRQN(_num)); \
251 } \
252 static struct max32_gpio_data max32_gpio_data_##_num; \
253 static const struct max32_gpio_config max32_gpio_config_##_num = { \
254 .common = \
255 { \
256 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(_num), \
257 }, \
258 .regs = (mxc_gpio_regs_t *)DT_INST_REG_ADDR(_num), \
259 .irq_func = &gpio_max32_irq_init_##_num, \
260 .clock = DEVICE_DT_GET_OR_NULL(DT_INST_CLOCKS_CTLR(_num)), \
261 .perclk.bus = DT_INST_PHA_BY_IDX_OR(_num, clocks, 0, offset, 0), \
262 .perclk.bit = DT_INST_PHA_BY_IDX_OR(_num, clocks, 1, bit, 0), \
263 }; \
264 DEVICE_DT_INST_DEFINE(_num, gpio_max32_init, NULL, &max32_gpio_data_##_num, \
265 &max32_gpio_config_##_num, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
266 (void *)&gpio_max32_driver);
267
268 DT_INST_FOREACH_STATUS_OKAY(MAX32_GPIO_INIT)
269