1 /*
2 * Copyright 2020 Broadcom
3 * Copyright 2024 Meta
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT brcm_iproc_gpio
9
10 #include <zephyr/arch/common/sys_bitops.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/drivers/gpio/gpio_utils.h>
14 #include <zephyr/irq.h>
15 #include <zephyr/kernel.h>
16
17 #define IPROC_GPIO_DATA_IN_OFFSET 0x00
18 #define IPROC_GPIO_DATA_OUT_OFFSET 0x04
19 #define IPROC_GPIO_OUT_EN_OFFSET 0x08
20 #define IPROC_GPIO_INT_TYPE_OFFSET 0x0c
21 #define IPROC_GPIO_INT_DE_OFFSET 0x10
22 #define IPROC_GPIO_INT_EDGE_OFFSET 0x14
23 #define IPROC_GPIO_INT_MSK_OFFSET 0x18
24 #define IPROC_GPIO_INT_STAT_OFFSET 0x1c
25 #define IPROC_GPIO_INT_MSTAT_OFFSET 0x20
26 #define IPROC_GPIO_INT_CLR_OFFSET 0x24
27 #define IPROC_GPIO_PAD_RES_OFFSET 0x34
28 #define IPROC_GPIO_RES_EN_OFFSET 0x38
29
30 struct gpio_iproc_config {
31 /* gpio_driver_config needs to be first */
32 struct gpio_driver_config common;
33 mem_addr_t base;
34 void (*irq_config_func)(const struct device *dev);
35 };
36
37 struct gpio_iproc_data {
38 /* gpio_driver_data needs to be first */
39 struct gpio_driver_data common;
40 sys_slist_t cb;
41 };
42
43 #define DEV_CFG(dev) ((const struct gpio_iproc_config *const)(dev)->config)
44 #define DEV_DATA(dev) ((struct gpio_iproc_data *const)(dev)->data)
45
gpio_iproc_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)46 static int gpio_iproc_configure(const struct device *dev, gpio_pin_t pin, gpio_flags_t flags)
47 {
48 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
49 mem_addr_t base = cfg->base;
50
51 /* Setup the pin direcion. */
52 if (flags & GPIO_OUTPUT) {
53 /* configure pin for output */
54 sys_set_bit(base + IPROC_GPIO_OUT_EN_OFFSET, pin);
55 } else if (flags & GPIO_INPUT) {
56 /* configure pin for input */
57 sys_clear_bit(base + IPROC_GPIO_OUT_EN_OFFSET, pin);
58 }
59
60 return 0;
61 }
62
gpio_iproc_port_get_raw(const struct device * dev,uint32_t * value)63 static int gpio_iproc_port_get_raw(const struct device *dev, uint32_t *value)
64 {
65 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
66 mem_addr_t base = cfg->base;
67
68 *value = sys_read32(base + IPROC_GPIO_DATA_IN_OFFSET);
69
70 return 0;
71 }
72
gpio_iproc_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)73 static int gpio_iproc_port_set_masked_raw(const struct device *dev, uint32_t mask, uint32_t value)
74 {
75 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
76 mem_addr_t base = cfg->base;
77
78 value = sys_read32(base + IPROC_GPIO_DATA_OUT_OFFSET);
79 value = (value & (~mask)) | (value & mask);
80 sys_write32(value, base + IPROC_GPIO_DATA_OUT_OFFSET);
81
82 return 0;
83 }
84
gpio_iproc_port_set_bits_raw(const struct device * dev,uint32_t mask)85 static int gpio_iproc_port_set_bits_raw(const struct device *dev, uint32_t mask)
86 {
87 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
88 mem_addr_t base = cfg->base;
89
90 sys_write32(mask, base + IPROC_GPIO_DATA_OUT_OFFSET);
91
92 return 0;
93 }
94
gpio_iproc_port_clear_bits_raw(const struct device * dev,uint32_t mask)95 static int gpio_iproc_port_clear_bits_raw(const struct device *dev, uint32_t mask)
96 {
97 uint32_t value;
98 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
99 mem_addr_t base = cfg->base;
100
101 /* Clear pins. */
102 value = sys_read32(base + IPROC_GPIO_DATA_OUT_OFFSET);
103 value = (value & ~mask);
104 sys_write32(value, base + IPROC_GPIO_DATA_OUT_OFFSET);
105
106 return 0;
107 }
108
gpio_iproc_port_toggle_bits(const struct device * dev,uint32_t mask)109 static int gpio_iproc_port_toggle_bits(const struct device *dev, uint32_t mask)
110 {
111 uint32_t value;
112 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
113 mem_addr_t base = cfg->base;
114
115 /* toggles pins. */
116 value = sys_read32(base + IPROC_GPIO_DATA_OUT_OFFSET);
117 value = (value ^ mask);
118 sys_write32(value, base + IPROC_GPIO_DATA_OUT_OFFSET);
119
120 return 0;
121 }
122
gpio_iproc_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)123 static int gpio_iproc_pin_interrupt_configure(const struct device *dev, gpio_pin_t pin,
124 enum gpio_int_mode mode, enum gpio_int_trig trig)
125 {
126 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
127 mem_addr_t base = cfg->base;
128
129 /* check for interrupt configurations */
130 if (mode & GPIO_INT_ENABLE) {
131 if (mode & GPIO_INT_EDGE) {
132 sys_clear_bit(base + IPROC_GPIO_INT_TYPE_OFFSET, pin);
133 } else {
134 sys_set_bit(base + IPROC_GPIO_INT_TYPE_OFFSET, pin);
135 }
136
137 /* Generate interrupt of both falling/rising edge */
138 if (trig & GPIO_INT_EDGE_BOTH) {
139 sys_set_bit(base + IPROC_GPIO_INT_DE_OFFSET, pin);
140 } else if (trig & GPIO_INT_HIGH_1) {
141 /* Generate interrupt on rising edge */
142 sys_clear_bit(base + IPROC_GPIO_INT_DE_OFFSET, pin);
143 sys_set_bit(base + IPROC_GPIO_INT_EDGE_OFFSET, pin);
144 } else if (trig & GPIO_INT_LOW_0) {
145 /* Generate interrupt on falling edge */
146 sys_clear_bit(base + IPROC_GPIO_INT_DE_OFFSET, pin);
147 sys_clear_bit(base + IPROC_GPIO_INT_EDGE_OFFSET, pin);
148 }
149
150 /* Unmask the interrupt */
151 sys_clear_bit(base + IPROC_GPIO_INT_MSTAT_OFFSET, pin);
152 } else {
153 sys_set_bit(base + IPROC_GPIO_INT_MSK_OFFSET, pin);
154 }
155 return 0;
156 }
157
gpio_iproc_isr(const struct device * dev)158 static void gpio_iproc_isr(const struct device *dev)
159 {
160 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
161 mem_addr_t base = cfg->base;
162 struct gpio_iproc_data *context = dev->data;
163 uint32_t int_stat;
164
165 int_stat = sys_read32(base + IPROC_GPIO_INT_STAT_OFFSET);
166
167 /* Clear the source of the interrupt */
168 sys_write32(int_stat, base + IPROC_GPIO_INT_CLR_OFFSET);
169
170 /* Handle the interrupt */
171 gpio_fire_callbacks(&context->cb, dev, int_stat);
172 }
173
gpio_iproc_manage_callback(const struct device * port,struct gpio_callback * callback,bool set)174 static int gpio_iproc_manage_callback(const struct device *port, struct gpio_callback *callback,
175 bool set)
176 {
177 struct gpio_iproc_data *context = port->data;
178
179 return gpio_manage_callback(&context->cb, callback, set);
180 }
181
182 static DEVICE_API(gpio, gpio_iproc_api) = {
183 .pin_configure = gpio_iproc_configure,
184 .port_get_raw = gpio_iproc_port_get_raw,
185 .port_set_masked_raw = gpio_iproc_port_set_masked_raw,
186 .port_set_bits_raw = gpio_iproc_port_set_bits_raw,
187 .port_clear_bits_raw = gpio_iproc_port_clear_bits_raw,
188 .port_toggle_bits = gpio_iproc_port_toggle_bits,
189 .pin_interrupt_configure = gpio_iproc_pin_interrupt_configure,
190 .manage_callback = gpio_iproc_manage_callback,
191 };
192
gpio_iproc_init(const struct device * dev)193 int gpio_iproc_init(const struct device *dev)
194 {
195 const struct gpio_iproc_config *const cfg = DEV_CFG(dev);
196
197 cfg->irq_config_func(dev);
198
199 return 0;
200 }
201
202 #define GPIO_IPROC_INIT(n) \
203 static void port_iproc_config_func_##n(const struct device *dev) \
204 { \
205 IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_iproc_isr, \
206 DEVICE_DT_INST_GET(n), 0); \
207 irq_enable(DT_INST_IRQN(n)); \
208 } \
209 \
210 static const struct gpio_iproc_config gpio_port_config_##n = { \
211 .common = \
212 { \
213 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
214 }, \
215 .base = DT_INST_REG_ADDR(n), \
216 .irq_config_func = port_iproc_config_func_##n, \
217 }; \
218 \
219 static struct gpio_iproc_data gpio_port_data_##n; \
220 \
221 DEVICE_DT_INST_DEFINE(n, gpio_iproc_init, NULL, &gpio_port_data_##n, \
222 &gpio_port_config_##n, POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \
223 &gpio_iproc_api);
224
225 DT_INST_FOREACH_STATUS_OKAY(GPIO_IPROC_INIT)
226