1 /*
2 * Copyright (c) 2022 Microchip Technology Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT microchip_mpfs_gpio
8
9 #include <errno.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/sys/util.h>
14 #include <zephyr/irq.h>
15
16 #include <zephyr/drivers/gpio/gpio_utils.h>
17
18
19 #define MSS_GPIO_INPUT_MODE 0x02
20 #define MSS_GPIO_OUTPUT_MODE 0x05
21 #define MSS_GPIO_INOUT_MODE 0x03
22 #define MSS_GPIO_IRQ_LEVEL_HIGH 0x00
23 #define MSS_GPIO_IRQ_LEVEL_LOW 0x20
24 #define MSS_GPIO_IRQ_EDGE_POSITIVE 0x40
25 #define MSS_GPIO_IRQ_EDGE_NEGATIVE 0x60
26 #define MSS_GPIO_IRQ_EDGE_BOTH 0x80
27 #define MSS_GPIO_INT_ENABLE_MASK 0x08
28 #define MSS_OUTPUT_BUFFER_ENABLE_MASK 0x04
29
30 struct mss_gpio_t {
31 uint32_t gpio_cfg[32];
32 uint32_t gpio_irq;
33 const uint32_t gpio_in;
34 uint32_t gpio_out;
35 uint32_t gpio_cfg_all;
36 uint32_t gpio_cfg_byte[4];
37 uint32_t gpio_clr_bits;
38 uint32_t gpio_set_bits;
39
40 };
41
42 typedef void (*mss_gpio_cfg_func_t)(void);
43
44
45 struct mss_gpio_config {
46 /* gpio_driver_config needs to be first */
47 struct gpio_driver_config common;
48 uintptr_t gpio_base_addr;
49 uint32_t gpio_irq_base;
50 mss_gpio_cfg_func_t gpio_cfg_func;
51 };
52
53 struct mss_gpio_data {
54 /* gpio_driver_data needs to be first */
55 struct gpio_driver_data common;
56 /* list of callbacks */
57 sys_slist_t cb;
58 };
59
60
61 /* Helper Macros for GPIO */
62 #define DEV_GPIO_CFG(dev) \
63 ((const struct mss_gpio_config * const)(dev)->config)
64 #define DEV_GPIO(dev) \
65 ((volatile struct mss_gpio_t *)(DEV_GPIO_CFG(dev))->gpio_base_addr)
66 #define DEV_GPIO_DATA(dev) \
67 ((struct mss_gpio_data *)(dev)->data)
68
69
mss_gpio_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)70 static int mss_gpio_config(const struct device *dev,
71 gpio_pin_t pin,
72 gpio_flags_t flags)
73 {
74 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
75 uint32_t io_flags = flags & (GPIO_INPUT | GPIO_OUTPUT);
76
77 if (io_flags == GPIO_DISCONNECTED) {
78
79 return -ENOTSUP;
80 }
81
82 if (flags & GPIO_OUTPUT) {
83
84 gpio->gpio_cfg[pin] |= MSS_GPIO_OUTPUT_MODE;
85
86 if (flags & GPIO_OUTPUT_INIT_HIGH) {
87 gpio->gpio_out |= BIT(pin);
88
89 } else if (flags & GPIO_OUTPUT_INIT_LOW) {
90 gpio->gpio_out &= ~BIT(pin);
91
92 }
93
94 } else if (flags & GPIO_INPUT) {
95 gpio->gpio_cfg[pin] |= MSS_GPIO_INPUT_MODE;
96
97 } else {
98 return -ENOTSUP;
99 }
100
101 return 0;
102 }
103
mss_gpio_port_toggle_bits(const struct device * dev,gpio_port_pins_t mask)104 static int mss_gpio_port_toggle_bits(const struct device *dev,
105 gpio_port_pins_t mask)
106 {
107 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
108
109 gpio->gpio_out ^= mask;
110
111 return 0;
112 }
113
mss_gpio_port_get_raw(const struct device * dev,gpio_port_value_t * value)114 static int mss_gpio_port_get_raw(const struct device *dev,
115 gpio_port_value_t *value)
116 {
117 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
118
119 *value = gpio->gpio_in;
120
121 return 0;
122 }
123
mss_gpio_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)124 static int mss_gpio_port_set_masked_raw(const struct device *dev,
125 gpio_port_pins_t mask,
126 gpio_port_value_t value)
127 {
128 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
129
130 gpio->gpio_out = (gpio->gpio_out & ~mask) | (value & mask);
131
132 return 0;
133 }
134
mss_gpio_port_set_bits_raw(const struct device * dev,gpio_port_pins_t mask)135 static int mss_gpio_port_set_bits_raw(const struct device *dev,
136 gpio_port_pins_t mask)
137 {
138 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
139
140 gpio->gpio_out |= mask;
141
142 return 0;
143 }
144
mss_gpio_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t mask)145 static int mss_gpio_port_clear_bits_raw(const struct device *dev,
146 gpio_port_pins_t mask)
147 {
148 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
149
150 gpio->gpio_out &= ~mask;
151
152 return 0;
153 }
154
mss_gpio_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)155 static int mss_gpio_pin_interrupt_configure(const struct device *dev,
156 gpio_pin_t pin,
157 enum gpio_int_mode mode,
158 enum gpio_int_trig trig)
159 {
160 ARG_UNUSED(trig);
161 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
162
163 gpio->gpio_cfg[pin] |= (MSS_GPIO_INT_ENABLE_MASK);
164
165 switch (mode | trig) {
166 case GPIO_INT_EDGE_BOTH:
167 gpio->gpio_cfg[pin] |= (MSS_GPIO_IRQ_EDGE_BOTH);
168 break;
169 case GPIO_INT_EDGE_RISING:
170 gpio->gpio_cfg[pin] |= (MSS_GPIO_IRQ_EDGE_POSITIVE);
171 break;
172 case GPIO_INT_EDGE_FALLING:
173 gpio->gpio_cfg[pin] |= (MSS_GPIO_IRQ_EDGE_NEGATIVE);
174 break;
175 case GPIO_INT_LEVEL_LOW:
176 gpio->gpio_cfg[pin] |= (MSS_GPIO_IRQ_LEVEL_LOW);
177 break;
178 case GPIO_INT_LEVEL_HIGH:
179 gpio->gpio_cfg[pin] |= (MSS_GPIO_IRQ_LEVEL_HIGH);
180 break;
181 default:
182 gpio->gpio_cfg[pin] &= ~MSS_GPIO_INT_ENABLE_MASK;
183 break;
184 }
185 return 0;
186 }
187
188
mss_gpio_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)189 static int mss_gpio_manage_callback(const struct device *dev,
190 struct gpio_callback *callback,
191 bool set)
192 {
193 struct mss_gpio_data *data = dev->data;
194
195 return gpio_manage_callback(&data->cb, callback, set);
196 }
197 static const struct gpio_driver_api mss_gpio_driver = {
198 .pin_configure = mss_gpio_config,
199 .port_toggle_bits = mss_gpio_port_toggle_bits,
200 .port_get_raw = mss_gpio_port_get_raw,
201 .port_set_masked_raw = mss_gpio_port_set_masked_raw,
202 .port_set_bits_raw = mss_gpio_port_set_bits_raw,
203 .port_clear_bits_raw = mss_gpio_port_clear_bits_raw,
204 .pin_interrupt_configure = mss_gpio_pin_interrupt_configure,
205 .manage_callback = mss_gpio_manage_callback
206 };
207
208
mss_gpio_init(const struct device * dev)209 static int mss_gpio_init(const struct device *dev)
210 {
211 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
212
213 gpio->gpio_irq = 0xFFFFFFFFU;
214
215 const struct mss_gpio_config *cfg = DEV_GPIO_CFG(dev);
216 /* Configure GPIO device */
217 cfg->gpio_cfg_func();
218 return 0;
219 }
220
mss_gpio_irq_handler(const struct device * dev)221 static void mss_gpio_irq_handler(const struct device *dev)
222 {
223 volatile struct mss_gpio_t *gpio = DEV_GPIO(dev);
224 uint32_t interrupt_status = gpio->gpio_irq;
225
226 gpio->gpio_irq = gpio->gpio_irq;
227 struct mss_gpio_data *data = dev->data;
228
229 gpio_fire_callbacks(&data->cb, dev, interrupt_status);
230 }
231
232 #define MSS_GPIO_INIT(n) \
233 static struct mss_gpio_data mss_gpio_data_##n; \
234 static void gpio_mss_gpio_cfg_func_##n(void); \
235 \
236 static const struct mss_gpio_config mss_gpio_config_##n = { \
237 .common = { \
238 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
239 }, \
240 .gpio_base_addr = DT_INST_REG_ADDR(n), \
241 .gpio_irq_base = DT_INST_IRQN(n), \
242 .gpio_cfg_func = gpio_mss_gpio_cfg_func_##n \
243 }; \
244 \
245 DEVICE_DT_INST_DEFINE(n, \
246 mss_gpio_init, \
247 NULL, \
248 &mss_gpio_data_##n, &mss_gpio_config_##n, \
249 PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, \
250 &mss_gpio_driver); \
251 \
252 static void gpio_mss_gpio_cfg_func_##n(void) \
253 { \
254 IRQ_CONNECT(DT_INST_IRQN(n), \
255 DT_INST_IRQ(n, priority), \
256 mss_gpio_irq_handler, \
257 DEVICE_DT_INST_GET(n), \
258 0); \
259 irq_enable(DT_INST_IRQN(n)); \
260 } \
261
262 DT_INST_FOREACH_STATUS_OKAY(MSS_GPIO_INIT)
263