1 /*
2  * Copyright (c) 2016 Linaro Limited.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT arm_cmsdk_gpio
8 
9 #include <zephyr/kernel.h>
10 
11 #include <zephyr/device.h>
12 #include <errno.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/init.h>
15 #include <soc.h>
16 #include <zephyr/drivers/clock_control/arm_clock_control.h>
17 #include <zephyr/drivers/gpio/gpio_cmsdk_ahb.h>
18 #include <zephyr/irq.h>
19 
20 #include <zephyr/drivers/gpio/gpio_utils.h>
21 
22 /**
23  * @brief GPIO driver for ARM CMSDK AHB GPIO
24  */
25 
26 typedef void (*gpio_config_func_t)(const struct device *port);
27 
28 struct gpio_cmsdk_ahb_cfg {
29 	/* gpio_driver_config needs to be first */
30 	struct gpio_driver_config common;
31 	volatile struct gpio_cmsdk_ahb *port;
32 	gpio_config_func_t gpio_config_func;
33 	/* GPIO Clock control in Active State */
34 	struct arm_clock_control_t gpio_cc_as;
35 	/* GPIO Clock control in Sleep State */
36 	struct arm_clock_control_t gpio_cc_ss;
37 	/* GPIO Clock control in Deep Sleep State */
38 	struct arm_clock_control_t gpio_cc_dss;
39 };
40 
41 struct gpio_cmsdk_ahb_dev_data {
42 	/* gpio_driver_data needs to be first */
43 	struct gpio_driver_data common;
44 	/* list of callbacks */
45 	sys_slist_t gpio_cb;
46 };
47 
gpio_cmsdk_ahb_port_get_raw(const struct device * dev,uint32_t * value)48 static int gpio_cmsdk_ahb_port_get_raw(const struct device *dev,
49 				       uint32_t *value)
50 {
51 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
52 
53 	*value = cfg->port->data;
54 
55 	return 0;
56 }
57 
gpio_cmsdk_ahb_port_set_masked_raw(const struct device * dev,uint32_t mask,uint32_t value)58 static int gpio_cmsdk_ahb_port_set_masked_raw(const struct device *dev,
59 					      uint32_t mask,
60 					      uint32_t value)
61 {
62 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
63 
64 	cfg->port->dataout = (cfg->port->dataout & ~mask) | (mask & value);
65 
66 	return 0;
67 }
68 
gpio_cmsdk_ahb_port_set_bits_raw(const struct device * dev,uint32_t mask)69 static int gpio_cmsdk_ahb_port_set_bits_raw(const struct device *dev,
70 					    uint32_t mask)
71 {
72 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
73 
74 	cfg->port->dataout |= mask;
75 
76 	return 0;
77 }
78 
gpio_cmsdk_ahb_port_clear_bits_raw(const struct device * dev,uint32_t mask)79 static int gpio_cmsdk_ahb_port_clear_bits_raw(const struct device *dev,
80 					      uint32_t mask)
81 {
82 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
83 
84 	cfg->port->dataout &= ~mask;
85 
86 	return 0;
87 }
88 
gpio_cmsdk_ahb_port_toggle_bits(const struct device * dev,uint32_t mask)89 static int gpio_cmsdk_ahb_port_toggle_bits(const struct device *dev,
90 					   uint32_t mask)
91 {
92 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
93 
94 	cfg->port->dataout ^= mask;
95 
96 	return 0;
97 }
98 
cmsdk_ahb_gpio_config(const struct device * dev,uint32_t mask,gpio_flags_t flags)99 static int cmsdk_ahb_gpio_config(const struct device *dev, uint32_t mask,
100 				 gpio_flags_t flags)
101 {
102 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
103 
104 	if (((flags & GPIO_INPUT) == 0) && ((flags & GPIO_OUTPUT) == 0)) {
105 		return -ENOTSUP;
106 	}
107 
108 	if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0) {
109 		return -ENOTSUP;
110 	}
111 
112 	if ((flags & GPIO_SINGLE_ENDED) != 0) {
113 		return -ENOTSUP;
114 	}
115 
116 	/*
117 	 * Setup the pin direction
118 	 * Output Enable:
119 	 * 0 - Input
120 	 * 1 - Output
121 	 */
122 	if ((flags & GPIO_OUTPUT) != 0) {
123 		if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0) {
124 			gpio_cmsdk_ahb_port_set_bits_raw(dev, mask);
125 		} else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0) {
126 			gpio_cmsdk_ahb_port_clear_bits_raw(dev, mask);
127 		}
128 		cfg->port->outenableset = mask;
129 	} else {
130 		cfg->port->outenableclr = mask;
131 	}
132 
133 	cfg->port->altfuncclr = mask;
134 
135 	return 0;
136 }
137 
138 /**
139  * @brief Configure pin or port
140  *
141  * @param dev Device struct
142  * @param pin The pin number
143  * @param flags Flags of pin or port
144  *
145  * @return 0 if successful, failed otherwise
146  */
gpio_cmsdk_ahb_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)147 static int gpio_cmsdk_ahb_config(const struct device *dev,
148 				 gpio_pin_t pin,
149 				 gpio_flags_t flags)
150 {
151 	return cmsdk_ahb_gpio_config(dev, BIT(pin), flags);
152 }
153 
gpio_cmsdk_ahb_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)154 static int gpio_cmsdk_ahb_pin_interrupt_configure(const struct device *dev,
155 						  gpio_pin_t pin,
156 						  enum gpio_int_mode mode,
157 						  enum gpio_int_trig trig)
158 {
159 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
160 
161 	if (trig == GPIO_INT_TRIG_BOTH) {
162 		return -ENOTSUP;
163 	}
164 
165 	/* For now treat level interrupts as not supported, as we seem to only
166 	 * get a single 'edge' still interrupt rather than continuous
167 	 * interrupts until the cause is cleared */
168 	if (mode == GPIO_INT_MODE_LEVEL) {
169 		return -ENOTSUP;
170 	}
171 
172 	if (mode == GPIO_INT_MODE_DISABLED) {
173 		cfg->port->intenclr = BIT(pin);
174 	} else {
175 		if (mode == GPIO_INT_MODE_EDGE) {
176 			cfg->port->inttypeset = BIT(pin);
177 		} else {
178 			/* LEVEL */
179 			cfg->port->inttypeclr = BIT(pin);
180 		}
181 
182 		/* Level High or Edge Rising */
183 		if (trig == GPIO_INT_TRIG_HIGH) {
184 			cfg->port->intpolset = BIT(pin);
185 		} else {
186 			cfg->port->intpolclr = BIT(pin);
187 		}
188 		cfg->port->intclear = BIT(pin);
189 		cfg->port->intenset = BIT(pin);
190 	}
191 
192 	return 0;
193 }
194 
gpio_cmsdk_ahb_isr(const struct device * dev)195 static void gpio_cmsdk_ahb_isr(const struct device *dev)
196 {
197 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
198 	struct gpio_cmsdk_ahb_dev_data *data = dev->data;
199 	uint32_t int_stat;
200 
201 	int_stat = cfg->port->intstatus;
202 
203 	/* clear the port interrupts */
204 	cfg->port->intclear = int_stat;
205 
206 	gpio_fire_callbacks(&data->gpio_cb, dev, int_stat);
207 
208 }
209 
gpio_cmsdk_ahb_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)210 static int gpio_cmsdk_ahb_manage_callback(const struct device *dev,
211 					  struct gpio_callback *callback,
212 					  bool set)
213 {
214 	struct gpio_cmsdk_ahb_dev_data *data = dev->data;
215 
216 	return gpio_manage_callback(&data->gpio_cb, callback, set);
217 }
218 
219 static const struct gpio_driver_api gpio_cmsdk_ahb_drv_api_funcs = {
220 	.pin_configure = gpio_cmsdk_ahb_config,
221 	.port_get_raw = gpio_cmsdk_ahb_port_get_raw,
222 	.port_set_masked_raw = gpio_cmsdk_ahb_port_set_masked_raw,
223 	.port_set_bits_raw = gpio_cmsdk_ahb_port_set_bits_raw,
224 	.port_clear_bits_raw = gpio_cmsdk_ahb_port_clear_bits_raw,
225 	.port_toggle_bits = gpio_cmsdk_ahb_port_toggle_bits,
226 	.pin_interrupt_configure = gpio_cmsdk_ahb_pin_interrupt_configure,
227 	.manage_callback = gpio_cmsdk_ahb_manage_callback,
228 };
229 
230 /**
231  * @brief Initialization function of GPIO
232  *
233  * @param dev Device struct
234  * @return 0 if successful, failed otherwise.
235  */
gpio_cmsdk_ahb_init(const struct device * dev)236 static int gpio_cmsdk_ahb_init(const struct device *dev)
237 {
238 	const struct gpio_cmsdk_ahb_cfg * const cfg = dev->config;
239 
240 #ifdef CONFIG_CLOCK_CONTROL
241 	/* Enable clock for subsystem */
242 	const struct device *const clk = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0));
243 
244 	if (!device_is_ready(clk)) {
245 		return -ENODEV;
246 	}
247 
248 #ifdef CONFIG_SOC_SERIES_BEETLE
249 	clock_control_on(clk, (clock_control_subsys_t) &cfg->gpio_cc_as);
250 	clock_control_off(clk, (clock_control_subsys_t) &cfg->gpio_cc_ss);
251 	clock_control_off(clk, (clock_control_subsys_t) &cfg->gpio_cc_dss);
252 #endif /* CONFIG_SOC_SERIES_BEETLE */
253 #endif /* CONFIG_CLOCK_CONTROL */
254 
255 	cfg->gpio_config_func(dev);
256 
257 	return 0;
258 }
259 
260 #define CMSDK_AHB_GPIO_DEVICE(n)						\
261 	static void gpio_cmsdk_port_##n##_config_func(const struct device *dev); \
262 										\
263 	static const struct gpio_cmsdk_ahb_cfg gpio_cmsdk_port_##n##_config = {	\
264 		.common = {							\
265 			.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n),	\
266 		},								\
267 		.port = ((volatile struct gpio_cmsdk_ahb *)DT_INST_REG_ADDR(n)),\
268 		.gpio_config_func = gpio_cmsdk_port_##n##_config_func,		\
269 		.gpio_cc_as = {.bus = CMSDK_AHB, .state = SOC_ACTIVE,		\
270 			       .device = DT_INST_REG_ADDR(n),},			\
271 		.gpio_cc_ss = {.bus = CMSDK_AHB, .state = SOC_SLEEP,		\
272 			       .device = DT_INST_REG_ADDR(n),},			\
273 		.gpio_cc_dss = {.bus = CMSDK_AHB, .state = SOC_DEEPSLEEP,	\
274 				.device = DT_INST_REG_ADDR(n),},		\
275 	};									\
276 										\
277 	static struct gpio_cmsdk_ahb_dev_data gpio_cmsdk_port_##n##_data;	\
278 										\
279 	DEVICE_DT_INST_DEFINE(n,						\
280 			    gpio_cmsdk_ahb_init,				\
281 			    NULL,						\
282 			    &gpio_cmsdk_port_##n##_data,			\
283 			    &gpio_cmsdk_port_## n ##_config,			\
284 			    PRE_KERNEL_1, CONFIG_GPIO_INIT_PRIORITY,	\
285 			    &gpio_cmsdk_ahb_drv_api_funcs);			\
286 										\
287 	static void gpio_cmsdk_port_##n##_config_func(const struct device *dev)	\
288 	{									\
289 		IRQ_CONNECT(DT_INST_IRQN(n),					\
290 			    DT_INST_IRQ(n, priority),				\
291 			    gpio_cmsdk_ahb_isr,					\
292 			    DEVICE_DT_INST_GET(n), 0);				\
293 										\
294 		irq_enable(DT_INST_IRQN(n));					\
295 	}
296 
297 DT_INST_FOREACH_STATUS_OKAY(CMSDK_AHB_GPIO_DEVICE)
298