1 /*
2  * Copyright (c) 2018 Zilogic Systems.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ti_stellaris_gpio
8 
9 #include <errno.h>
10 #include <zephyr/arch/cpu.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/irq.h>
14 #include <soc.h>
15 #include <zephyr/sys/sys_io.h>
16 #include <zephyr/drivers/gpio/gpio_utils.h>
17 
18 typedef void (*config_func_t)(const struct device *dev);
19 
20 struct gpio_stellaris_config {
21 	/* gpio_driver_config needs to be first */
22 	struct gpio_driver_config common;
23 	uint32_t base;
24 	uint32_t port_map;
25 	config_func_t config_func;
26 };
27 
28 struct gpio_stellaris_runtime {
29 	/* gpio_driver_data needs to be first */
30 	struct gpio_driver_data common;
31 	sys_slist_t cb;
32 };
33 
34 #define GPIO_REG_ADDR(base, offset) (base + offset)
35 
36 #define GPIO_RW_ADDR(base, offset, p)			 \
37 	(GPIO_REG_ADDR(base, offset) | (1 << (p + 2)))
38 
39 #define GPIO_RW_MASK_ADDR(base, offset, mask)		 \
40 	(GPIO_REG_ADDR(base, offset) | (mask << 2))
41 
42 enum gpio_regs {
43 	GPIO_DATA_OFFSET = 0x000,
44 	GPIO_DIR_OFFSET = 0x400,
45 	GPIO_DEN_OFFSET = 0x51C,
46 	GPIO_IS_OFFSET = 0x404,
47 	GPIO_IBE_OFFSET = 0x408,
48 	GPIO_IEV_OFFSET = 0x40C,
49 	GPIO_IM_OFFSET = 0x410,
50 	GPIO_MIS_OFFSET = 0x418,
51 	GPIO_ICR_OFFSET = 0x41C,
52 };
53 
gpio_stellaris_isr(const struct device * dev)54 static void gpio_stellaris_isr(const struct device *dev)
55 {
56 	const struct gpio_stellaris_config * const cfg = dev->config;
57 	struct gpio_stellaris_runtime *context = dev->data;
58 	uint32_t base = cfg->base;
59 	uint32_t int_stat = sys_read32(GPIO_REG_ADDR(base, GPIO_MIS_OFFSET));
60 
61 	gpio_fire_callbacks(&context->cb, dev, int_stat);
62 
63 	sys_write32(int_stat, GPIO_REG_ADDR(base, GPIO_ICR_OFFSET));
64 }
65 
gpio_stellaris_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)66 static int gpio_stellaris_configure(const struct device *dev,
67 				    gpio_pin_t pin, gpio_flags_t flags)
68 {
69 	const struct gpio_stellaris_config *cfg = dev->config;
70 	uint32_t base = cfg->base;
71 	uint32_t port_map = cfg->port_map;
72 
73 	if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) {
74 		return -ENOTSUP;
75 	}
76 
77 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
78 		return -ENOTSUP;
79 	}
80 
81 	/* Check for pin availability */
82 	if (!sys_test_bit((uint32_t)&port_map, pin)) {
83 		return -EINVAL;
84 	}
85 
86 	if ((flags & GPIO_OUTPUT) != 0) {
87 		mm_reg_t mask_addr;
88 
89 		mask_addr = GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, BIT(pin));
90 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
91 			sys_write32(BIT(pin), mask_addr);
92 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
93 			sys_write32(0, mask_addr);
94 		}
95 		sys_set_bit(GPIO_REG_ADDR(base, GPIO_DIR_OFFSET), pin);
96 		/* Pin digital enable */
97 		sys_set_bit(GPIO_REG_ADDR(base, GPIO_DEN_OFFSET), pin);
98 	} else if ((flags & GPIO_INPUT) != 0) {
99 		sys_clear_bit(GPIO_REG_ADDR(base, GPIO_DIR_OFFSET), pin);
100 		/* Pin digital enable */
101 		sys_set_bit(GPIO_REG_ADDR(base, GPIO_DEN_OFFSET), pin);
102 	} else {
103 		/* Pin digital disable */
104 		sys_clear_bit(GPIO_REG_ADDR(base, GPIO_DEN_OFFSET), pin);
105 	}
106 
107 	return 0;
108 }
109 
110 #ifdef CONFIG_GPIO_GET_CONFIG
gpio_stellaris_get_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t * out_flags)111 static int gpio_stellaris_get_config(const struct device *dev,
112 				 gpio_pin_t pin,
113 				 gpio_flags_t *out_flags)
114 {
115 	const struct gpio_stellaris_config *cfg = dev->config;
116 	uint32_t base = cfg->base;
117 	gpio_flags_t flags = 0;
118 	mm_reg_t mask_addr;
119 
120 	if (sys_test_bit(GPIO_REG_ADDR(base, GPIO_DEN_OFFSET), pin) == 0) {
121 		flags = GPIO_DISCONNECTED;
122 	} else if (sys_test_bit(GPIO_REG_ADDR(base, GPIO_DIR_OFFSET), pin)) {
123 		mask_addr = GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, BIT(pin));
124 
125 		if (sys_test_bit(mask_addr, pin)) {
126 			flags |= GPIO_OUTPUT_HIGH;
127 		} else {
128 			flags |= GPIO_OUTPUT_LOW;
129 		}
130 	} else {
131 		flags = GPIO_INPUT;
132 	}
133 	*out_flags = flags;
134 	return 0;
135 }
136 #endif
137 
gpio_stellaris_port_get_raw(const struct device * dev,uint32_t * value)138 static int gpio_stellaris_port_get_raw(const struct device *dev,
139 				       uint32_t *value)
140 {
141 	const struct gpio_stellaris_config *cfg = dev->config;
142 	uint32_t base = cfg->base;
143 
144 	*value = sys_read32(GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, 0xff));
145 
146 	return 0;
147 }
148 
gpio_stellaris_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)149 static int gpio_stellaris_port_set_masked_raw(const struct device *dev,
150 					      uint32_t mask,
151 					      uint32_t value)
152 {
153 	const struct gpio_stellaris_config *cfg = dev->config;
154 	uint32_t base = cfg->base;
155 
156 	sys_write32(value, GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, mask));
157 
158 	return 0;
159 }
160 
gpio_stellaris_port_set_bits_raw(const struct device * dev,uint32_t mask)161 static int gpio_stellaris_port_set_bits_raw(const struct device *dev,
162 					    uint32_t mask)
163 {
164 	const struct gpio_stellaris_config *cfg = dev->config;
165 	uint32_t base = cfg->base;
166 
167 	sys_write32(mask, GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, mask));
168 
169 	return 0;
170 }
171 
gpio_stellaris_port_clear_bits_raw(const struct device * dev,uint32_t mask)172 static int gpio_stellaris_port_clear_bits_raw(const struct device *dev,
173 					      uint32_t mask)
174 {
175 	const struct gpio_stellaris_config *cfg = dev->config;
176 	uint32_t base = cfg->base;
177 
178 	sys_write32(0, GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, mask));
179 
180 	return 0;
181 }
182 
gpio_stellaris_port_toggle_bits(const struct device * dev,uint32_t mask)183 static int gpio_stellaris_port_toggle_bits(const struct device *dev,
184 					   uint32_t mask)
185 {
186 	const struct gpio_stellaris_config *cfg = dev->config;
187 	uint32_t base = cfg->base;
188 	uint32_t value;
189 
190 	value = sys_read32(GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, 0xff));
191 	value ^= mask;
192 	sys_write32(value, GPIO_RW_MASK_ADDR(base, GPIO_DATA_OFFSET, 0xff));
193 
194 	return 0;
195 }
196 
gpio_stellaris_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)197 static int gpio_stellaris_pin_interrupt_configure(const struct device *dev,
198 						  gpio_pin_t pin,
199 						  enum gpio_int_mode mode,
200 						  enum gpio_int_trig trig)
201 {
202 	const struct gpio_stellaris_config *cfg = dev->config;
203 	uint32_t base = cfg->base;
204 
205 	/* Check if GPIO port needs interrupt support */
206 	if (mode == GPIO_INT_MODE_DISABLED) {
207 		/* Set the mask to disable the interrupt */
208 		sys_set_bit(GPIO_REG_ADDR(base, GPIO_IM_OFFSET), pin);
209 	} else {
210 		if (mode == GPIO_INT_MODE_EDGE) {
211 			sys_clear_bit(GPIO_REG_ADDR(base, GPIO_IS_OFFSET), pin);
212 		} else {
213 			sys_set_bit(GPIO_REG_ADDR(base, GPIO_IS_OFFSET), pin);
214 		}
215 
216 		if (trig == GPIO_INT_TRIG_BOTH) {
217 			sys_set_bit(GPIO_REG_ADDR(base, GPIO_IBE_OFFSET), pin);
218 		} else if (trig == GPIO_INT_TRIG_HIGH) {
219 			sys_set_bit(GPIO_REG_ADDR(base, GPIO_IEV_OFFSET), pin);
220 		} else {
221 			sys_clear_bit(GPIO_REG_ADDR(base,
222 						    GPIO_IEV_OFFSET), pin);
223 		}
224 		/* Clear the Mask to enable the interrupt */
225 		sys_clear_bit(GPIO_REG_ADDR(base, GPIO_IM_OFFSET), pin);
226 	}
227 
228 	return 0;
229 }
230 
gpio_stellaris_init(const struct device * dev)231 static int gpio_stellaris_init(const struct device *dev)
232 {
233 	const struct gpio_stellaris_config *cfg = dev->config;
234 
235 	cfg->config_func(dev);
236 	return 0;
237 }
238 
gpio_stellaris_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)239 static int gpio_stellaris_manage_callback(const struct device *dev,
240 					  struct gpio_callback *callback,
241 					  bool set)
242 {
243 	struct gpio_stellaris_runtime *context = dev->data;
244 
245 	gpio_manage_callback(&context->cb, callback, set);
246 
247 	return 0;
248 }
249 
250 static const struct gpio_driver_api gpio_stellaris_driver_api = {
251 	.pin_configure = gpio_stellaris_configure,
252 #ifdef CONFIG_GPIO_GET_CONFIG
253 	.pin_get_config = gpio_stellaris_get_config,
254 #endif
255 	.port_get_raw = gpio_stellaris_port_get_raw,
256 	.port_set_masked_raw = gpio_stellaris_port_set_masked_raw,
257 	.port_set_bits_raw = gpio_stellaris_port_set_bits_raw,
258 	.port_clear_bits_raw = gpio_stellaris_port_clear_bits_raw,
259 	.port_toggle_bits = gpio_stellaris_port_toggle_bits,
260 	.pin_interrupt_configure = gpio_stellaris_pin_interrupt_configure,
261 	.manage_callback = gpio_stellaris_manage_callback,
262 };
263 
264 #define STELLARIS_GPIO_DEVICE(n)							\
265 	static void port_## n ##_stellaris_config_func(const struct device *dev);		\
266 											\
267 	static struct gpio_stellaris_runtime port_## n ##_stellaris_runtime;		\
268 											\
269 	static const struct gpio_stellaris_config gpio_stellaris_port_## n ##_config = {\
270 		.common = {								\
271 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),		\
272 		},									\
273 		.base = DT_INST_REG_ADDR(n),			\
274 		.port_map = BIT_MASK(DT_INST_PROP(n, ngpios)),		\
275 		.config_func = port_## n ##_stellaris_config_func,			\
276 	};										\
277 											\
278 	DEVICE_DT_INST_DEFINE(n,							\
279 			    gpio_stellaris_init,					\
280 			    NULL,							\
281 			    &port_## n ##_stellaris_runtime,				\
282 			    &gpio_stellaris_port_## n ##_config,			\
283 			    POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY,			\
284 			    &gpio_stellaris_driver_api);				\
285 											\
286 	static void port_## n ##_stellaris_config_func(const struct device *dev)		\
287 	{										\
288 		IRQ_CONNECT(DT_INST_IRQN(n),			\
289 			    DT_INST_IRQ(n, priority),		\
290 			    gpio_stellaris_isr,						\
291 			    DEVICE_DT_INST_GET(n), 0);					\
292 											\
293 		irq_enable(DT_INST_IRQN(n));			\
294 	}
295 
296 DT_INST_FOREACH_STATUS_OKAY(STELLARIS_GPIO_DEVICE)
297