1 /*
2  * Copyright (c) 2020-2023 IoT.bzh
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT renesas_rcar_gpio
8 
9 #include <errno.h>
10 
11 #include <zephyr/kernel.h>
12 #include <zephyr/device.h>
13 #include <zephyr/init.h>
14 #include <zephyr/drivers/gpio.h>
15 #include <zephyr/drivers/clock_control.h>
16 #include <zephyr/drivers/clock_control/renesas_cpg_mssr.h>
17 #include <zephyr/irq.h>
18 
19 #include <zephyr/drivers/gpio/gpio_utils.h>
20 
21 typedef void (*init_func_t)(const struct device *dev);
22 
23 /* Required by DEVICE_MMIO_NAMED_* macros */
24 #define DEV_CFG(_dev) \
25 	((const struct gpio_rcar_cfg *)(_dev)->config)
26 #define DEV_DATA(_dev) ((struct gpio_rcar_data *)(_dev)->data)
27 
28 struct gpio_rcar_cfg {
29 	struct gpio_driver_config common;
30 	DEVICE_MMIO_NAMED_ROM(reg_base);
31 	init_func_t init_func;
32 	const struct device *clock_dev;
33 	struct rcar_cpg_clk mod_clk;
34 };
35 
36 struct gpio_rcar_data {
37 	struct gpio_driver_data common;
38 	DEVICE_MMIO_NAMED_RAM(reg_base);
39 	sys_slist_t cb;
40 };
41 
42 #define IOINTSEL 0x00   /* General IO/Interrupt Switching Register */
43 #define INOUTSEL 0x04   /* General Input/Output Switching Register */
44 #define OUTDT    0x08   /* General Output Register */
45 #define INDT     0x0c   /* General Input Register */
46 #define INTDT    0x10   /* Interrupt Display Register */
47 #define INTCLR   0x14   /* Interrupt Clear Register */
48 #define INTMSK   0x18   /* Interrupt Mask Register */
49 #define MSKCLR   0x1c   /* Interrupt Mask Clear Register */
50 #define POSNEG   0x20   /* Positive/Negative Logic Select Register */
51 #define EDGLEVEL 0x24   /* Edge/level Select Register */
52 #define FILONOFF 0x28   /* Chattering Prevention On/Off Register */
53 #define OUTDTSEL 0x40   /* Output Data Select Register */
54 #define BOTHEDGE 0x4c   /* One Edge/Both Edge Select Register */
55 #define INEN     0x50	/* General Input Enable Register */
56 
gpio_rcar_read(const struct device * dev,uint32_t offs)57 static inline uint32_t gpio_rcar_read(const struct device *dev, uint32_t offs)
58 {
59 	return sys_read32(DEVICE_MMIO_NAMED_GET(dev, reg_base) + offs);
60 }
61 
gpio_rcar_write(const struct device * dev,uint32_t offs,uint32_t value)62 static inline void gpio_rcar_write(const struct device *dev, uint32_t offs, uint32_t value)
63 {
64 	sys_write32(value, DEVICE_MMIO_NAMED_GET(dev, reg_base) + offs);
65 }
66 
gpio_rcar_modify_bit(const struct device * dev,uint32_t offs,int bit,bool value)67 static void gpio_rcar_modify_bit(const struct device *dev,
68 				 uint32_t offs, int bit, bool value)
69 {
70 	uint32_t tmp = gpio_rcar_read(dev, offs);
71 
72 	if (value) {
73 		tmp |= BIT(bit);
74 	} else {
75 		tmp &= ~BIT(bit);
76 	}
77 
78 	gpio_rcar_write(dev, offs, tmp);
79 }
80 
gpio_rcar_port_isr(const struct device * dev)81 static void gpio_rcar_port_isr(const struct device *dev)
82 {
83 	struct gpio_rcar_data *data = dev->data;
84 	uint32_t pending, fsb, mask;
85 
86 	pending = gpio_rcar_read(dev, INTDT);
87 	mask = gpio_rcar_read(dev, INTMSK);
88 
89 	while ((pending = gpio_rcar_read(dev, INTDT) &
90 			  gpio_rcar_read(dev, INTMSK))) {
91 		fsb = find_lsb_set(pending) - 1;
92 		gpio_fire_callbacks(&data->cb, dev, BIT(fsb));
93 		gpio_rcar_write(dev, INTCLR, BIT(fsb));
94 	}
95 }
96 
gpio_rcar_config_general_input_output_mode(const struct device * dev,uint32_t gpio,bool output)97 static void gpio_rcar_config_general_input_output_mode(
98 	const struct device *dev,
99 	uint32_t gpio,
100 	bool output)
101 {
102 	/* follow steps in the GPIO documentation for
103 	 * "Setting General Output Mode" and
104 	 * "Setting General Input Mode"
105 	 */
106 
107 	/* Configure positive logic in POSNEG */
108 	gpio_rcar_modify_bit(dev, POSNEG, gpio, false);
109 
110 	/* Select "Input Enable/Disable" in INEN for Gen4 SoCs */
111 #ifdef CONFIG_SOC_SERIES_RCAR_GEN4
112 	gpio_rcar_modify_bit(dev, INEN, gpio, !output);
113 #endif
114 
115 	/* Select "General Input/Output Mode" in IOINTSEL */
116 	gpio_rcar_modify_bit(dev, IOINTSEL, gpio, false);
117 
118 	/* Select Input Mode or Output Mode in INOUTSEL */
119 	gpio_rcar_modify_bit(dev, INOUTSEL, gpio, output);
120 
121 	/* Select General Output Register to output data in OUTDTSEL */
122 	if (output) {
123 		gpio_rcar_modify_bit(dev, OUTDTSEL, gpio, false);
124 	}
125 }
126 
gpio_rcar_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)127 static int gpio_rcar_configure(const struct device *dev,
128 			       gpio_pin_t pin, gpio_flags_t flags)
129 {
130 	if ((flags & GPIO_OUTPUT) && (flags & GPIO_INPUT)) {
131 		/* Pin cannot be configured as input and output */
132 		return -ENOTSUP;
133 	} else if (!(flags & (GPIO_INPUT | GPIO_OUTPUT))) {
134 		/* Pin has to be configured as input or output */
135 		return -ENOTSUP;
136 	}
137 
138 	if (flags & GPIO_OUTPUT) {
139 		if (flags & GPIO_OUTPUT_INIT_HIGH) {
140 			gpio_rcar_modify_bit(dev, OUTDT, pin, true);
141 		} else if (flags & GPIO_OUTPUT_INIT_LOW) {
142 			gpio_rcar_modify_bit(dev, OUTDT, pin, false);
143 		}
144 		gpio_rcar_config_general_input_output_mode(dev, pin, true);
145 	} else {
146 		gpio_rcar_config_general_input_output_mode(dev, pin, false);
147 	}
148 
149 	return 0;
150 }
151 
gpio_rcar_port_get_raw(const struct device * dev,gpio_port_value_t * value)152 static int gpio_rcar_port_get_raw(const struct device *dev,
153 				  gpio_port_value_t *value)
154 {
155 	*value = gpio_rcar_read(dev, INDT);
156 	return 0;
157 }
158 
gpio_rcar_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)159 static int gpio_rcar_port_set_masked_raw(const struct device *dev,
160 					 gpio_port_pins_t mask,
161 					 gpio_port_value_t value)
162 {
163 	uint32_t port_val;
164 
165 	port_val = gpio_rcar_read(dev, OUTDT);
166 	port_val = (port_val & ~mask) | (value & mask);
167 	gpio_rcar_write(dev, OUTDT, port_val);
168 
169 	return 0;
170 }
171 
gpio_rcar_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)172 static int gpio_rcar_port_set_bits_raw(const struct device *dev,
173 				       gpio_port_pins_t pins)
174 {
175 	uint32_t port_val;
176 
177 	port_val = gpio_rcar_read(dev, OUTDT);
178 	port_val |= pins;
179 	gpio_rcar_write(dev, OUTDT, port_val);
180 
181 	return 0;
182 }
183 
gpio_rcar_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)184 static int gpio_rcar_port_clear_bits_raw(const struct device *dev,
185 					 gpio_port_pins_t pins)
186 {
187 	uint32_t port_val;
188 
189 	port_val = gpio_rcar_read(dev, OUTDT);
190 	port_val &= ~pins;
191 	gpio_rcar_write(dev, OUTDT, port_val);
192 
193 	return 0;
194 }
195 
gpio_rcar_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)196 static int gpio_rcar_port_toggle_bits(const struct device *dev,
197 				      gpio_port_pins_t pins)
198 {
199 	uint32_t port_val;
200 
201 	port_val = gpio_rcar_read(dev, OUTDT);
202 	port_val ^= pins;
203 	gpio_rcar_write(dev, OUTDT, port_val);
204 
205 	return 0;
206 }
207 
gpio_rcar_pin_interrupt_configure(const struct device * dev,gpio_pin_t pin,enum gpio_int_mode mode,enum gpio_int_trig trig)208 static int gpio_rcar_pin_interrupt_configure(const struct device *dev,
209 					     gpio_pin_t pin,
210 					     enum gpio_int_mode mode,
211 					     enum gpio_int_trig trig)
212 {
213 	if (mode == GPIO_INT_MODE_DISABLED) {
214 		return -ENOTSUP;
215 	}
216 
217 	/* Configure positive or negative logic in POSNEG */
218 	gpio_rcar_modify_bit(dev, POSNEG, pin,
219 			     (trig == GPIO_INT_TRIG_LOW));
220 
221 	/* Configure edge or level trigger in EDGLEVEL */
222 	if (mode == GPIO_INT_MODE_EDGE) {
223 		gpio_rcar_modify_bit(dev, EDGLEVEL, pin, true);
224 	} else {
225 		gpio_rcar_modify_bit(dev, EDGLEVEL, pin, false);
226 	}
227 
228 	if (trig == GPIO_INT_TRIG_BOTH) {
229 		gpio_rcar_modify_bit(dev, BOTHEDGE, pin, true);
230 	}
231 
232 	/* Select "Input Enable" in INEN for Gen4 SoCs */
233 #ifdef CONFIG_SOC_SERIES_RCAR_GEN4
234 	gpio_rcar_modify_bit(dev, INEN, pin, true);
235 #endif
236 
237 	gpio_rcar_modify_bit(dev, IOINTSEL, pin, true);
238 
239 	if (mode == GPIO_INT_MODE_EDGE) {
240 		/* Write INTCLR in case of edge trigger */
241 		gpio_rcar_write(dev, INTCLR, BIT(pin));
242 	}
243 
244 	gpio_rcar_write(dev, MSKCLR, BIT(pin));
245 
246 	return 0;
247 }
248 
gpio_rcar_init(const struct device * dev)249 static int gpio_rcar_init(const struct device *dev)
250 {
251 	const struct gpio_rcar_cfg *config = dev->config;
252 	int ret;
253 
254 	if (!device_is_ready(config->clock_dev)) {
255 		return -ENODEV;
256 	}
257 
258 	ret = clock_control_on(config->clock_dev,
259 			       (clock_control_subsys_t) &config->mod_clk);
260 
261 	if (ret < 0) {
262 		return ret;
263 	}
264 
265 	DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE);
266 	config->init_func(dev);
267 	return 0;
268 }
269 
gpio_rcar_manage_callback(const struct device * dev,struct gpio_callback * callback,bool set)270 static int gpio_rcar_manage_callback(const struct device *dev,
271 				     struct gpio_callback *callback,
272 				     bool set)
273 {
274 	struct gpio_rcar_data *data = dev->data;
275 
276 	return gpio_manage_callback(&data->cb, callback, set);
277 }
278 
279 static const struct gpio_driver_api gpio_rcar_driver_api = {
280 	.pin_configure = gpio_rcar_configure,
281 	.port_get_raw = gpio_rcar_port_get_raw,
282 	.port_set_masked_raw = gpio_rcar_port_set_masked_raw,
283 	.port_set_bits_raw = gpio_rcar_port_set_bits_raw,
284 	.port_clear_bits_raw = gpio_rcar_port_clear_bits_raw,
285 	.port_toggle_bits = gpio_rcar_port_toggle_bits,
286 	.pin_interrupt_configure = gpio_rcar_pin_interrupt_configure,
287 	.manage_callback = gpio_rcar_manage_callback,
288 };
289 
290 /* Device Instantiation */
291 #define GPIO_RCAR_INIT(n)					      \
292 	static void gpio_rcar_##n##_init(const struct device *dev);   \
293 	static const struct gpio_rcar_cfg gpio_rcar_cfg_##n = {	      \
294 		DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \
295 		.common = {					      \
296 			.port_pin_mask =			      \
297 				GPIO_PORT_PIN_MASK_FROM_DT_INST(n),   \
298 		},						      \
299 		.init_func = gpio_rcar_##n##_init,		      \
300 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),   \
301 		.mod_clk.module =				      \
302 			DT_INST_CLOCKS_CELL_BY_IDX(n, 0, module),     \
303 		.mod_clk.domain =				      \
304 			DT_INST_CLOCKS_CELL_BY_IDX(n, 0, domain),     \
305 	};							      \
306 	static struct gpio_rcar_data gpio_rcar_data_##n;	      \
307 								      \
308 	DEVICE_DT_INST_DEFINE(n,				      \
309 			      gpio_rcar_init,			      \
310 			      NULL,				      \
311 			      &gpio_rcar_data_##n,		      \
312 			      &gpio_rcar_cfg_##n,		      \
313 			      PRE_KERNEL_1,			      \
314 			      CONFIG_GPIO_INIT_PRIORITY,	      \
315 			      &gpio_rcar_driver_api		      \
316 			      );				      \
317 	static void gpio_rcar_##n##_init(const struct device *dev)    \
318 	{							      \
319 		IRQ_CONNECT(DT_INST_IRQN(n),			      \
320 			    0,					      \
321 			    gpio_rcar_port_isr,			      \
322 			    DEVICE_DT_INST_GET(n), 0);		      \
323 								      \
324 		irq_enable(DT_INST_IRQN(n));			      \
325 	}
326 
327 DT_INST_FOREACH_STATUS_OKAY(GPIO_RCAR_INIT)
328