1 /*
2 * Copyright (c) 2023 Antmicro <www.antmicro.com>
3 * Copyright (c) 2023 Ambiq Micro Inc. <www.ambiq.com>
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT ambiq_gpio_bank
9
10 #include <errno.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/drivers/gpio/gpio_utils.h>
14 #include <zephyr/irq.h>
15 #include <zephyr/spinlock.h>
16
17 #include <am_mcu_apollo.h>
18
19 typedef void (*ambiq_gpio_cfg_func_t)(void);
20
21 struct ambiq_gpio_config {
22 struct gpio_driver_config common;
23 uint32_t base;
24 uint32_t offset;
25 uint32_t irq_num;
26 ambiq_gpio_cfg_func_t cfg_func;
27 uint8_t ngpios;
28 };
29
30 struct ambiq_gpio_data {
31 struct gpio_driver_data common;
32 sys_slist_t cb;
33 struct k_spinlock lock;
34 };
35
ambiq_gpio_pin_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)36 static int ambiq_gpio_pin_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
37 {
38 const struct ambiq_gpio_config *const dev_cfg = dev->config;
39
40 pin += (dev_cfg->offset >> 2);
41
42 am_hal_gpio_pincfg_t pincfg = am_hal_gpio_pincfg_default;
43
44 if (flags & GPIO_INPUT) {
45 pincfg = am_hal_gpio_pincfg_input;
46 if (flags & GPIO_PULL_UP) {
47 pincfg.GP.cfg_b.ePullup = AM_HAL_GPIO_PIN_PULLUP_50K;
48 } else if (flags & GPIO_PULL_DOWN) {
49 pincfg.GP.cfg_b.ePullup = AM_HAL_GPIO_PIN_PULLDOWN_50K;
50 }
51 }
52 if (flags & GPIO_OUTPUT) {
53 if (flags & GPIO_SINGLE_ENDED) {
54 if (flags & GPIO_LINE_OPEN_DRAIN) {
55 pincfg.GP.cfg_b.eGPOutCfg = AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN;
56 }
57 } else {
58 pincfg.GP.cfg_b.eGPOutCfg = AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL;
59 }
60 }
61 if (flags & GPIO_DISCONNECTED) {
62 pincfg = am_hal_gpio_pincfg_disabled;
63 }
64
65 if (flags & GPIO_OUTPUT_INIT_HIGH) {
66 pincfg.GP.cfg_b.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH;
67 am_hal_gpio_state_write(pin, AM_HAL_GPIO_OUTPUT_SET);
68
69 } else if (flags & GPIO_OUTPUT_INIT_LOW) {
70 pincfg.GP.cfg_b.eCEpol = AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW;
71 am_hal_gpio_state_write(pin, AM_HAL_GPIO_OUTPUT_CLEAR);
72 }
73
74 am_hal_gpio_pinconfig(pin, pincfg);
75
76 return 0;
77 }
78
79 #ifdef CONFIG_GPIO_GET_CONFIG
ambiq_gpio_get_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t * out_flags)80 static int ambiq_gpio_get_config(const struct device *dev, gpio_pin_t pin, gpio_flags_t *out_flags)
81 {
82 const struct ambiq_gpio_config *const dev_cfg = dev->config;
83 am_hal_gpio_pincfg_t pincfg;
84
85 pin += (dev_cfg->offset >> 2);
86
87 am_hal_gpio_pinconfig_get(pin, &pincfg);
88
89 if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_DISABLE &&
90 pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_NONE) {
91 *out_flags = GPIO_DISCONNECTED;
92 }
93 if (pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_ENABLE) {
94 *out_flags = GPIO_INPUT;
95 if (pincfg.GP.cfg_b.ePullup == AM_HAL_GPIO_PIN_PULLUP_50K) {
96 *out_flags |= GPIO_PULL_UP;
97 } else if (pincfg.GP.cfg_b.ePullup == AM_HAL_GPIO_PIN_PULLDOWN_50K) {
98 *out_flags |= GPIO_PULL_DOWN;
99 }
100 }
101 if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL) {
102 *out_flags = GPIO_OUTPUT | GPIO_PUSH_PULL;
103 if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH) {
104 *out_flags |= GPIO_OUTPUT_HIGH;
105 } else if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW) {
106 *out_flags |= GPIO_OUTPUT_LOW;
107 }
108 }
109 if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) {
110 *out_flags = GPIO_OUTPUT | GPIO_OPEN_DRAIN;
111 if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVEHIGH) {
112 *out_flags |= GPIO_OUTPUT_HIGH;
113 } else if (pincfg.GP.cfg_b.eCEpol == AM_HAL_GPIO_PIN_CEPOL_ACTIVELOW) {
114 *out_flags |= GPIO_OUTPUT_LOW;
115 }
116 }
117
118 return 0;
119 }
120 #endif
121
122 #ifdef CONFIG_GPIO_GET_DIRECTION
ambiq_gpio_port_get_direction(const struct device * dev,gpio_port_pins_t map,gpio_port_pins_t * inputs,gpio_port_pins_t * outputs)123 static int ambiq_gpio_port_get_direction(const struct device *dev, gpio_port_pins_t map,
124 gpio_port_pins_t *inputs, gpio_port_pins_t *outputs)
125 {
126 const struct ambiq_gpio_config *const dev_cfg = dev->config;
127 am_hal_gpio_pincfg_t pincfg;
128 gpio_port_pins_t ip = 0;
129 gpio_port_pins_t op = 0;
130 uint32_t pin_offset = dev_cfg->offset >> 2;
131
132 if (inputs != NULL) {
133 for (int i = 0; i < dev_cfg->ngpios; i++) {
134 if ((map >> i) & 1) {
135 am_hal_gpio_pinconfig_get(i + pin_offset, &pincfg);
136 if (pincfg.GP.cfg_b.eGPInput == AM_HAL_GPIO_PIN_INPUT_ENABLE) {
137 ip |= BIT(i);
138 }
139 }
140 }
141 *inputs = ip;
142 }
143 if (outputs != NULL) {
144 for (int i = 0; i < dev_cfg->ngpios; i++) {
145 if ((map >> i) & 1) {
146 am_hal_gpio_pinconfig_get(i + pin_offset, &pincfg);
147 if (pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_PUSHPULL ||
148 pincfg.GP.cfg_b.eGPOutCfg == AM_HAL_GPIO_PIN_OUTCFG_OPENDRAIN) {
149 op |= BIT(i);
150 }
151 }
152 }
153 *outputs = op;
154 }
155
156 return 0;
157 }
158 #endif
159
ambiq_gpio_port_get_raw(const struct device * dev,gpio_port_value_t * value)160 static int ambiq_gpio_port_get_raw(const struct device *dev, gpio_port_value_t *value)
161 {
162 const struct ambiq_gpio_config *const dev_cfg = dev->config;
163
164 *value = (*AM_HAL_GPIO_RDn(dev_cfg->offset >> 2));
165
166 return 0;
167 }
168
ambiq_gpio_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)169 static int ambiq_gpio_port_set_masked_raw(const struct device *dev, gpio_port_pins_t mask,
170 gpio_port_value_t value)
171 {
172 const struct ambiq_gpio_config *const dev_cfg = dev->config;
173 uint32_t pin_offset = dev_cfg->offset >> 2;
174
175 for (int i = 0; i < dev_cfg->ngpios; i++) {
176 if ((mask >> i) & 1) {
177 am_hal_gpio_state_write(i + pin_offset, ((value >> i) & 1));
178 }
179 }
180
181 return 0;
182 }
183
ambiq_gpio_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)184 static int ambiq_gpio_port_set_bits_raw(const struct device *dev, gpio_port_pins_t pins)
185 {
186 const struct ambiq_gpio_config *const dev_cfg = dev->config;
187 uint32_t pin_offset = dev_cfg->offset >> 2;
188
189 for (int i = 0; i < dev_cfg->ngpios; i++) {
190 if ((pins >> i) & 1) {
191 am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_SET);
192 }
193 }
194
195 return 0;
196 }
197
ambiq_gpio_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)198 static int ambiq_gpio_port_clear_bits_raw(const struct device *dev, gpio_port_pins_t pins)
199 {
200 const struct ambiq_gpio_config *const dev_cfg = dev->config;
201 uint32_t pin_offset = dev_cfg->offset >> 2;
202
203 for (int i = 0; i < dev_cfg->ngpios; i++) {
204 if ((pins >> i) & 1) {
205 am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_CLEAR);
206 }
207 }
208
209 return 0;
210 }
211
ambiq_gpio_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)212 static int ambiq_gpio_port_toggle_bits(const struct device *dev, gpio_port_pins_t pins)
213 {
214 const struct ambiq_gpio_config *const dev_cfg = dev->config;
215 uint32_t pin_offset = dev_cfg->offset >> 2;
216
217 for (int i = 0; i < dev_cfg->ngpios; i++) {
218 if ((pins >> i) & 1) {
219 am_hal_gpio_state_write(i + pin_offset, AM_HAL_GPIO_OUTPUT_TOGGLE);
220 }
221 }
222
223 return 0;
224 }
225
ambiq_gpio_isr(const struct device * dev)226 static void ambiq_gpio_isr(const struct device *dev)
227 {
228 struct ambiq_gpio_data *const data = dev->data;
229 const struct ambiq_gpio_config *const dev_cfg = dev->config;
230
231 uint32_t int_status;
232
233 am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status);
234 am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status);
235
236 gpio_fire_callbacks(&data->cb, dev, int_status);
237 }
238
ambiq_gpio_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)239 static int ambiq_gpio_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
240 enum gpio_int_mode mode, enum gpio_int_trig trig)
241 {
242 const struct ambiq_gpio_config *const dev_cfg = dev->config;
243 struct ambiq_gpio_data *const data = dev->data;
244
245 am_hal_gpio_pincfg_t pincfg;
246 int gpio_pin = pin + (dev_cfg->offset >> 2);
247 uint32_t int_status;
248 int ret;
249
250 ret = am_hal_gpio_pinconfig_get(gpio_pin, &pincfg);
251
252 if (mode == GPIO_INT_MODE_DISABLED) {
253 pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_NONE;
254 ret = am_hal_gpio_pinconfig(gpio_pin, pincfg);
255
256 k_spinlock_key_t key = k_spin_lock(&data->lock);
257
258 ret = am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status);
259 ret = am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status);
260 ret = am_hal_gpio_interrupt_control(AM_HAL_GPIO_INT_CHANNEL_0,
261 AM_HAL_GPIO_INT_CTRL_INDV_DISABLE,
262 (void *)&gpio_pin);
263 k_spin_unlock(&data->lock, key);
264
265 } else {
266 if (mode == GPIO_INT_MODE_LEVEL) {
267 return -ENOTSUP;
268 }
269 switch (trig) {
270 case GPIO_INT_TRIG_LOW:
271 pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_HI2LO;
272 break;
273 case GPIO_INT_TRIG_HIGH:
274 pincfg.GP.cfg_b.eIntDir = AM_HAL_GPIO_PIN_INTDIR_LO2HI;
275 break;
276 case GPIO_INT_TRIG_BOTH:
277 /*
278 * GPIO_INT_TRIG_BOTH is not supported on Ambiq Apollo4 Plus Platform
279 * ERR008: GPIO: Dual-edge interrupts are not vectoring
280 */
281 return -ENOTSUP;
282 }
283 ret = am_hal_gpio_pinconfig(gpio_pin, pincfg);
284
285 irq_enable(dev_cfg->irq_num);
286
287 k_spinlock_key_t key = k_spin_lock(&data->lock);
288
289 ret = am_hal_gpio_interrupt_irq_status_get(dev_cfg->irq_num, false, &int_status);
290 ret = am_hal_gpio_interrupt_irq_clear(dev_cfg->irq_num, int_status);
291 ret = am_hal_gpio_interrupt_control(AM_HAL_GPIO_INT_CHANNEL_0,
292 AM_HAL_GPIO_INT_CTRL_INDV_ENABLE,
293 (void *)&gpio_pin);
294 k_spin_unlock(&data->lock, key);
295 }
296 return ret;
297 }
298
ambiq_gpio_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)299 static int ambiq_gpio_manage_callback(const struct device *dev, struct gpio_callback *callback,
300 bool set)
301 {
302 struct ambiq_gpio_data *const data = dev->data;
303
304 return gpio_manage_callback(&data->cb, callback, set);
305 }
306
ambiq_gpio_init(const struct device * port)307 static int ambiq_gpio_init(const struct device *port)
308 {
309 const struct ambiq_gpio_config *const dev_cfg = port->config;
310
311 NVIC_ClearPendingIRQ(dev_cfg->irq_num);
312
313 dev_cfg->cfg_func();
314
315 return 0;
316 }
317
318 static const struct gpio_driver_api ambiq_gpio_drv_api = {
319 .pin_configure = ambiq_gpio_pin_configure,
320 #ifdef CONFIG_GPIO_GET_CONFIG
321 .pin_get_config = ambiq_gpio_get_config,
322 #endif
323 .port_get_raw = ambiq_gpio_port_get_raw,
324 .port_set_masked_raw = ambiq_gpio_port_set_masked_raw,
325 .port_set_bits_raw = ambiq_gpio_port_set_bits_raw,
326 .port_clear_bits_raw = ambiq_gpio_port_clear_bits_raw,
327 .port_toggle_bits = ambiq_gpio_port_toggle_bits,
328 .pin_interrupt_configure = ambiq_gpio_pin_interrupt_configure,
329 .manage_callback = ambiq_gpio_manage_callback,
330 #ifdef CONFIG_GPIO_GET_DIRECTION
331 .port_get_direction = ambiq_gpio_port_get_direction,
332 #endif
333 };
334
335 #define AMBIQ_GPIO_DEFINE(n) \
336 static struct ambiq_gpio_data ambiq_gpio_data_##n; \
337 static void ambiq_gpio_cfg_func_##n(void); \
338 \
339 static const struct ambiq_gpio_config ambiq_gpio_config_##n = { \
340 .common = \
341 { \
342 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
343 }, \
344 .base = DT_REG_ADDR(DT_INST_PARENT(n)), \
345 .offset = DT_INST_REG_ADDR(n), \
346 .ngpios = DT_INST_PROP(n, ngpios), \
347 .irq_num = DT_INST_IRQN(n), \
348 .cfg_func = ambiq_gpio_cfg_func_##n}; \
349 static void ambiq_gpio_cfg_func_##n(void) \
350 { \
351 \
352 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), ambiq_gpio_isr, \
353 DEVICE_DT_INST_GET(n), 0); \
354 \
355 return; \
356 }; \
357 \
358 DEVICE_DT_INST_DEFINE(n, &ambiq_gpio_init, NULL, &ambiq_gpio_data_##n, \
359 &ambiq_gpio_config_##n, PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
360 &ambiq_gpio_drv_api);
361
362 DT_INST_FOREACH_STATUS_OKAY(AMBIQ_GPIO_DEFINE)
363