1 /*
2 * Copyright (c) 2024 Texas Instruments Incorporated
3 * Copyright (c) 2024 BayLibre, SAS
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT ti_cc23x0_gpio
9
10 #include <zephyr/types.h>
11 #include <zephyr/device.h>
12 #include <zephyr/irq.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/drivers/gpio/gpio_utils.h>
15
16 #include <driverlib/clkctl.h>
17 #include <driverlib/gpio.h>
18 #include <inc/hw_ioc.h>
19
20 #define IOC_ADDR(index) (IOC_BASE + IOC_O_IOC0 + (sizeof(uint32_t) * (index)))
21
22 struct gpio_cc23x0_config {
23 /* gpio_driver_config needs to be first */
24 struct gpio_driver_config common;
25 };
26
27 struct gpio_cc23x0_data {
28 /* gpio_driver_data needs to be first */
29 struct gpio_driver_data common;
30 sys_slist_t callbacks;
31 };
32
set_pin_mask_non_atomic(uint8_t index,uint32_t registerBaseAddress)33 static void set_pin_mask_non_atomic(uint8_t index, uint32_t registerBaseAddress)
34 {
35 GPIOSetConfigDio(GPIO_BASE + registerBaseAddress, BIT(index));
36 }
37
gpio_cc23x0_config(const struct device * port,gpio_pin_t pin,gpio_flags_t flags)38 static int gpio_cc23x0_config(const struct device *port, gpio_pin_t pin, gpio_flags_t flags)
39 {
40 uint32_t config = 0;
41 uint32_t iocfg_reg = IOC_ADDR(pin);
42 gpio_flags_t direction = flags & GPIO_DIR_MASK;
43
44 if (flags & GPIO_PULL_UP) {
45 config |= IOC_IOC0_PULLCTL_PULL_UP;
46 } else if (flags & GPIO_PULL_DOWN) {
47 config |= IOC_IOC0_PULLCTL_PULL_DOWN;
48 } else {
49 config |= IOC_IOC0_PULLCTL_PULL_DIS;
50 }
51
52 if (!(flags & GPIO_SINGLE_ENDED)) {
53 config |= IOC_IOC0_IOMODE_NORMAL;
54 } else {
55 if (flags & GPIO_LINE_OPEN_DRAIN) {
56 config |= IOC_IOC0_IOMODE_OPEND;
57 } else {
58 config |= IOC_IOC0_IOMODE_OPENS;
59 }
60 }
61 if (direction & GPIO_INPUT) {
62 config |= IOC_IOC0_INPEN_EN | IOC_IOC0_HYSTEN_EN;
63 }
64
65 GPIOSetConfigDio(iocfg_reg, config);
66
67 if (flags & GPIO_OUTPUT) {
68 if (flags & GPIO_OUTPUT_INIT_HIGH) {
69 GPIOSetDio(pin);
70 } else if (flags & GPIO_OUTPUT_INIT_LOW) {
71 GPIOClearDio(pin);
72 }
73 GPIOSetOutputEnableDio(pin, GPIO_OUTPUT_ENABLE);
74 } else {
75 GPIOSetOutputEnableDio(pin, GPIO_OUTPUT_DISABLE);
76 }
77 return 0;
78 }
79
80 #ifdef CONFIG_GPIO_GET_CONFIG
gpio_cc23x0_get_config(const struct device * port,gpio_pin_t pin,gpio_flags_t * flags)81 static int gpio_cc23x0_get_config(const struct device *port, gpio_pin_t pin, gpio_flags_t *flags)
82 {
83 uint32_t out_flag = 0;
84 uint32_t iocfg_reg = IOC_ADDR(pin);
85 uint32_t config = GPIOGetConfigDio(iocfg_reg);
86
87 /* GPIO input/output configuration flags */
88 if (config & IOC_IOC0_INPEN_EN) {
89 out_flag |= GPIO_INPUT;
90 }
91
92 if (GPIOGetOutputEnableDio(pin)) {
93 out_flag |= GPIO_OUTPUT;
94
95 if (GPIOReadDio(pin)) {
96 out_flag |= GPIO_OUTPUT_INIT_HIGH;
97 } else {
98 /* This is the default value. If not explicitly set,
99 * the returned config will not be symmetric
100 */
101 out_flag |= GPIO_OUTPUT_INIT_LOW;
102 }
103 }
104
105 /* GPIO interrupt configuration flags */
106 if ((config & IOC_IOC0_EDGEDET_M) != IOC_IOC0_EDGEDET_EDGE_DIS) {
107 if (config & IOC_IOC0_EDGEDET_EDGE_POS) {
108 out_flag |= GPIO_INT_EDGE_RISING;
109 }
110
111 if (config & IOC_IOC0_EDGEDET_EDGE_NEG) {
112 out_flag |= GPIO_INT_EDGE_FALLING;
113 }
114 } else {
115 /* This is the default value. If not explicitly set,
116 * the returned config will not be symmetric
117 */
118 out_flag |= GPIO_INT_DISABLE;
119 }
120
121 /* GPIO pin drive flags */
122 if (config & IOC_IOC0_IOMODE_OPENS) {
123 out_flag |= GPIO_OPEN_SOURCE;
124 }
125
126 if (config & IOC_IOC0_IOMODE_OPEND) {
127 out_flag |= IOC_IOC0_IOMODE_OPEND;
128 }
129
130 if (config & IOC_IOC0_PULLCTL_PULL_UP) {
131 out_flag |= GPIO_PULL_UP;
132 }
133
134 if (config & IOC_IOC0_PULLCTL_PULL_DOWN) {
135 out_flag |= GPIO_PULL_DOWN;
136 }
137
138 *flags = out_flag;
139
140 return 0;
141 }
142 #endif
143
gpio_cc23x0_port_get_raw(const struct device * port,uint32_t * value)144 static int gpio_cc23x0_port_get_raw(const struct device *port, uint32_t *value)
145 {
146 *value = GPIOReadMultiDio(GPIO_DIO_ALL_MASK);
147
148 return 0;
149 }
150
gpio_cc23x0_port_set_masked_raw(const struct device * port,uint32_t mask,uint32_t value)151 static int gpio_cc23x0_port_set_masked_raw(const struct device *port, uint32_t mask, uint32_t value)
152 {
153 GPIOWriteMultiDio(mask, value);
154
155 return 0;
156 }
157
gpio_cc23x0_port_set_bits_raw(const struct device * port,uint32_t mask)158 static int gpio_cc23x0_port_set_bits_raw(const struct device *port, uint32_t mask)
159 {
160 GPIOSetMultiDio(mask);
161
162 return 0;
163 }
164
gpio_cc23x0_port_clear_bits_raw(const struct device * port,uint32_t mask)165 static int gpio_cc23x0_port_clear_bits_raw(const struct device *port, uint32_t mask)
166 {
167 GPIOClearMultiDio(mask);
168
169 return 0;
170 }
171
gpio_cc23x0_port_toggle_bits(const struct device * port,uint32_t mask)172 static int gpio_cc23x0_port_toggle_bits(const struct device *port, uint32_t mask)
173 {
174 GPIOToggleMultiDio(mask);
175
176 return 0;
177 }
178
gpio_cc23x0xx_pin_interrupt_configure(const struct device * port,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)179 static int gpio_cc23x0xx_pin_interrupt_configure(const struct device *port, gpio_pin_t pin,
180 enum gpio_int_mode mode, enum gpio_int_trig trig)
181 {
182 if (mode == GPIO_INT_MODE_LEVEL) {
183 return ENOTSUP;
184 }
185
186 uint32_t config = GPIOGetConfigDio(IOC_ADDR(pin)) & ~IOC_IOC0_EDGEDET_M;
187
188 if (mode == GPIO_INT_MODE_DISABLED) {
189 config |= IOC_IOC1_EDGEDET_EDGE_DIS;
190
191 GPIOSetConfigDio(IOC_ADDR(pin), config);
192
193 /* Disable interrupt mask */
194 set_pin_mask_non_atomic(pin, GPIO_O_IMCLR);
195
196 } else if (mode == GPIO_INT_MODE_EDGE) {
197 switch (trig) {
198 case GPIO_INT_TRIG_LOW:
199 config |= IOC_IOC1_EDGEDET_EDGE_NEG;
200 break;
201 case GPIO_INT_TRIG_HIGH:
202 config |= IOC_IOC1_EDGEDET_EDGE_POS;
203 break;
204 case GPIO_INT_TRIG_BOTH:
205 config |= IOC_IOC1_EDGEDET_EDGE_BOTH;
206 break;
207 default:
208 return ENOTSUP;
209 }
210
211 GPIOSetConfigDio(IOC_ADDR(pin), config);
212
213 /* Enable interrupt mask */
214 set_pin_mask_non_atomic(pin, GPIO_O_ICLR);
215 set_pin_mask_non_atomic(pin, GPIO_O_IMSET);
216 }
217
218 return 0;
219 }
220
gpio_cc23x0_manage_callback(const struct device * port,struct gpio_callback * callback,bool set)221 static int gpio_cc23x0_manage_callback(const struct device *port, struct gpio_callback *callback,
222 bool set)
223 {
224 struct gpio_cc23x0_data *data = port->data;
225
226 return gpio_manage_callback(&data->callbacks, callback, set);
227 }
228
gpio_cc23x0_get_pending_int(const struct device * dev)229 static uint32_t gpio_cc23x0_get_pending_int(const struct device *dev)
230 {
231 return GPIOGetEventMultiDio(GPIO_DIO_ALL_MASK);
232 }
233
gpio_cc23x0_isr(const struct device * dev)234 static void gpio_cc23x0_isr(const struct device *dev)
235 {
236 struct gpio_cc23x0_data *data = dev->data;
237
238 uint32_t status = GPIOGetEventMultiDio(GPIO_DIO_ALL_MASK);
239
240 GPIOClearEventMultiDio(status);
241
242 gpio_fire_callbacks(&data->callbacks, dev, status);
243 }
244
gpio_cc23x0_init(const struct device * dev)245 static int gpio_cc23x0_init(const struct device *dev)
246 {
247 /* Enable GPIO domain clock */
248 CLKCTLEnable(CLKCTL_BASE, CLKCTL_GPIO);
249
250 /* Enable IRQ */
251 IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), gpio_cc23x0_isr,
252 DEVICE_DT_INST_GET(0), 0);
253
254 irq_enable(DT_INST_IRQN(0));
255
256 return 0;
257 }
258
259 static DEVICE_API(gpio, gpio_cc23x0_driver_api) = {
260 .pin_configure = gpio_cc23x0_config,
261 #ifdef CONFIG_GPIO_GET_CONFIG
262 .pin_get_config = gpio_cc23x0_get_config,
263 #endif
264 .port_get_raw = gpio_cc23x0_port_get_raw,
265 .port_set_masked_raw = gpio_cc23x0_port_set_masked_raw,
266 .port_set_bits_raw = gpio_cc23x0_port_set_bits_raw,
267 .port_clear_bits_raw = gpio_cc23x0_port_clear_bits_raw,
268 .port_toggle_bits = gpio_cc23x0_port_toggle_bits,
269 .pin_interrupt_configure = gpio_cc23x0xx_pin_interrupt_configure,
270 .manage_callback = gpio_cc23x0_manage_callback,
271 .get_pending_int = gpio_cc23x0_get_pending_int,
272 };
273
274 static const struct gpio_cc23x0_config gpio_cc23x0_config_0 = {
275 .common = {/* Read ngpios from DT */
276 .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(0)}};
277
278 static struct gpio_cc23x0_data gpio_cc23x0_data_0;
279
280 DEVICE_DT_INST_DEFINE(0, gpio_cc23x0_init, NULL, &gpio_cc23x0_data_0, &gpio_cc23x0_config_0,
281 PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY, &gpio_cc23x0_driver_api);
282