1 /*
2  * Copyright (c) 2022 ITE Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT ite_it8xxx2_gpiokscan
8 
9 #include <errno.h>
10 #include <zephyr/device.h>
11 #include <zephyr/drivers/gpio.h>
12 #include <zephyr/drivers/gpio/gpio_utils.h>
13 #include <zephyr/dt-bindings/gpio/ite-it8xxx2-gpio.h>
14 #include <zephyr/irq.h>
15 #include <zephyr/sys/util.h>
16 #include <zephyr/types.h>
17 
18 struct gpio_kscan_cfg {
19 	/* The gpio_driver_config needs to be first */
20 	struct gpio_driver_config common;
21 	/* KSI[7:0]/KSO[15:8]/KSO[7:0] port gpio output enable register (bit mapping to pin) */
22 	volatile uint8_t *reg_ksi_kso_goen;
23 	/* KSI[7:0]/KSO[15:8]/KSO[7:0] port gpio control register (bit mapping to pin) */
24 	volatile uint8_t *reg_ksi_kso_gctrl;
25 	/* KSI[7:0]/KSO[15:8]/KSO[7:0] port gpio data register (bit mapping to pin) */
26 	volatile uint8_t *reg_ksi_kso_gdat;
27 	/* KSI[7:0]/KSO[15:8]/KSO[7:0] port gpio data mirror register (bit mapping to pin) */
28 	volatile uint8_t *reg_ksi_kso_gdmr;
29 	/* KSI[7:0]/KSO[15:8]/KSO[7:0] port gpio open drain register (bit mapping to pin) */
30 	volatile uint8_t *reg_ksi_kso_gpod;
31 };
32 
33 struct gpio_kscan_data {
34 	/* The gpio_driver_data needs to be first */
35 	struct gpio_driver_data common;
36 };
37 
gpio_kscan_it8xxx2_configure(const struct device * dev,gpio_pin_t pin,gpio_flags_t flags)38 static int gpio_kscan_it8xxx2_configure(const struct device *dev,
39 					gpio_pin_t pin,
40 					gpio_flags_t flags)
41 {
42 	const struct gpio_kscan_cfg *const config = dev->config;
43 	volatile uint8_t *reg_ksi_kso_gctrl = config->reg_ksi_kso_gctrl;
44 	volatile uint8_t *reg_ksi_kso_goen = config->reg_ksi_kso_goen;
45 	volatile uint8_t *reg_ksi_kso_gdat = config->reg_ksi_kso_gdat;
46 	volatile uint8_t *reg_ksi_kso_gpod = config->reg_ksi_kso_gpod;
47 	uint8_t mask = BIT(pin);
48 
49 	/* KSI[7:0]/KSO[15:8]/KSO[7:0] pins don't support open source, 1.8V and 5.0V mode */
50 	if ((((flags & GPIO_SINGLE_ENDED) != 0) && ((flags & GPIO_LINE_OPEN_DRAIN) == 0)) ||
51 	     ((flags & IT8XXX2_GPIO_VOLTAGE_MASK) == IT8XXX2_GPIO_VOLTAGE_1P8) ||
52 	     ((flags & IT8XXX2_GPIO_VOLTAGE_MASK) == IT8XXX2_GPIO_VOLTAGE_5P0)) {
53 		return -ENOTSUP;
54 	}
55 
56 	/* Set GPIO mode */
57 	*reg_ksi_kso_gctrl |= mask;
58 
59 	if (flags & GPIO_OUTPUT) {
60 		/*
61 		 * Select open drain first, so that we don't glitch the signal
62 		 * when changing the line to an output.
63 		 */
64 		if (flags & GPIO_OPEN_DRAIN) {
65 			/* Set open-drain and enable internal pullup */
66 			*reg_ksi_kso_gpod |= mask;
67 		} else {
68 			/* Set push-pull and disable internal pullup */
69 			*reg_ksi_kso_gpod &= ~mask;
70 		}
71 
72 		unsigned int key = irq_lock();
73 
74 		/* Set level before change to output */
75 		if (flags & GPIO_OUTPUT_INIT_HIGH) {
76 			*reg_ksi_kso_gdat |= mask;
77 		} else if (flags & GPIO_OUTPUT_INIT_LOW) {
78 			*reg_ksi_kso_gdat &= ~mask;
79 		}
80 
81 		irq_unlock(key);
82 
83 		/* Set output mode */
84 		*reg_ksi_kso_goen |= mask;
85 	} else {
86 		/* Set input mode */
87 		*reg_ksi_kso_goen  &= ~mask;
88 
89 		if (flags & GPIO_PULL_UP) {
90 			/* Enable internal pullup */
91 			*reg_ksi_kso_gpod |= mask;
92 		} else {
93 			/* No internal pullup and pulldown */
94 			*reg_ksi_kso_gpod &= ~mask;
95 		}
96 	}
97 
98 	return 0;
99 }
100 
101 #ifdef CONFIG_GPIO_GET_CONFIG
gpio_kscan_it8xxx2_get_config(const struct device * dev,gpio_pin_t pin,gpio_flags_t * out_flags)102 static int gpio_kscan_it8xxx2_get_config(const struct device *dev,
103 					 gpio_pin_t pin,
104 					 gpio_flags_t *out_flags)
105 {
106 	const struct gpio_kscan_cfg *const config = dev->config;
107 	volatile uint8_t *reg_ksi_kso_goen = config->reg_ksi_kso_goen;
108 	volatile uint8_t *reg_ksi_kso_gdat = config->reg_ksi_kso_gdat;
109 	volatile uint8_t *reg_ksi_kso_gpod = config->reg_ksi_kso_gpod;
110 	uint8_t mask = BIT(pin);
111 	gpio_flags_t flags = 0;
112 
113 	/* KSI[7:0]/KSO[15:8]/KSO[7:0] pins only support 3.3V */
114 	flags |= IT8XXX2_GPIO_VOLTAGE_3P3;
115 
116 	/* Input or output */
117 	if (*reg_ksi_kso_goen & mask) {
118 		flags |= GPIO_OUTPUT;
119 
120 		/* Open-drain or push-pull */
121 		if (*reg_ksi_kso_gpod & mask) {
122 			flags |= GPIO_OPEN_DRAIN;
123 		}
124 
125 		/* High or low */
126 		if (*reg_ksi_kso_gdat & mask) {
127 			flags |= GPIO_OUTPUT_HIGH;
128 		} else {
129 			flags |= GPIO_OUTPUT_LOW;
130 		}
131 	} else {
132 		flags |= GPIO_INPUT;
133 
134 		/* pullup or no pull */
135 		if (*reg_ksi_kso_gpod & mask) {
136 			flags |= GPIO_PULL_UP;
137 		}
138 	}
139 
140 	*out_flags = flags;
141 
142 	return 0;
143 }
144 #endif
145 
gpio_kscan_it8xxx2_port_get_raw(const struct device * dev,gpio_port_value_t * value)146 static int gpio_kscan_it8xxx2_port_get_raw(const struct device *dev,
147 					   gpio_port_value_t *value)
148 {
149 	const struct gpio_kscan_cfg *const config = dev->config;
150 	volatile uint8_t *reg_ksi_kso_gdmr = config->reg_ksi_kso_gdmr;
151 
152 	/* Get physical level from all pins of the port */
153 	*value = *reg_ksi_kso_gdmr;
154 
155 	return 0;
156 }
157 
gpio_kscan_it8xxx2_port_set_masked_raw(const struct device * dev,gpio_port_pins_t mask,gpio_port_value_t value)158 static int gpio_kscan_it8xxx2_port_set_masked_raw(const struct device *dev,
159 						  gpio_port_pins_t mask,
160 						  gpio_port_value_t value)
161 {
162 	const struct gpio_kscan_cfg *const config = dev->config;
163 	volatile uint8_t *reg_ksi_kso_gdat = config->reg_ksi_kso_gdat;
164 	unsigned int key = irq_lock();
165 	uint8_t out = *reg_ksi_kso_gdat;
166 
167 	/* Set high/low level to mask pins of the port */
168 	*reg_ksi_kso_gdat = ((out & ~mask) | (value & mask));
169 
170 	irq_unlock(key);
171 
172 	return 0;
173 }
174 
gpio_kscan_it8xxx2_port_set_bits_raw(const struct device * dev,gpio_port_pins_t pins)175 static int gpio_kscan_it8xxx2_port_set_bits_raw(const struct device *dev,
176 						gpio_port_pins_t pins)
177 {
178 	const struct gpio_kscan_cfg *const config = dev->config;
179 	volatile uint8_t *reg_ksi_kso_gdat = config->reg_ksi_kso_gdat;
180 	unsigned int key = irq_lock();
181 
182 	/* Set high level to pins of the port */
183 	*reg_ksi_kso_gdat |= pins;
184 
185 	irq_unlock(key);
186 
187 	return 0;
188 }
189 
gpio_kscan_it8xxx2_port_clear_bits_raw(const struct device * dev,gpio_port_pins_t pins)190 static int gpio_kscan_it8xxx2_port_clear_bits_raw(const struct device *dev,
191 						  gpio_port_pins_t pins)
192 {
193 	const struct gpio_kscan_cfg *const config = dev->config;
194 	volatile uint8_t *reg_ksi_kso_gdat = config->reg_ksi_kso_gdat;
195 	unsigned int key = irq_lock();
196 
197 	/* Set low level to pins of the port */
198 	*reg_ksi_kso_gdat &= ~pins;
199 
200 	irq_unlock(key);
201 
202 	return 0;
203 }
204 
gpio_kscan_it8xxx2_port_toggle_bits(const struct device * dev,gpio_port_pins_t pins)205 static int gpio_kscan_it8xxx2_port_toggle_bits(const struct device *dev,
206 					       gpio_port_pins_t pins)
207 {
208 	const struct gpio_kscan_cfg *const config = dev->config;
209 	volatile uint8_t *reg_ksi_kso_gdat = config->reg_ksi_kso_gdat;
210 	unsigned int key = irq_lock();
211 
212 	/* Toggle output level to pins of the port */
213 	*reg_ksi_kso_gdat ^= pins;
214 
215 	irq_unlock(key);
216 
217 	return 0;
218 }
219 
220 static const struct gpio_driver_api gpio_kscan_it8xxx2_driver_api = {
221 	.pin_configure = gpio_kscan_it8xxx2_configure,
222 #ifdef CONFIG_GPIO_GET_CONFIG
223 	.pin_get_config = gpio_kscan_it8xxx2_get_config,
224 #endif
225 	.port_get_raw = gpio_kscan_it8xxx2_port_get_raw,
226 	.port_set_masked_raw = gpio_kscan_it8xxx2_port_set_masked_raw,
227 	.port_set_bits_raw = gpio_kscan_it8xxx2_port_set_bits_raw,
228 	.port_clear_bits_raw = gpio_kscan_it8xxx2_port_clear_bits_raw,
229 	.port_toggle_bits = gpio_kscan_it8xxx2_port_toggle_bits,
230 };
231 
232 #define GPIO_KSCAN_IT8XXX2_INIT(inst)                                          \
233 static const struct gpio_kscan_cfg gpio_kscan_it8xxx2_cfg_##inst = {           \
234 	.common = {                                                            \
235 		.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_NGPIOS(               \
236 				 DT_INST_PROP(inst, ngpios))                   \
237 	},                                                                     \
238 	.reg_ksi_kso_goen = (uint8_t *)DT_INST_REG_ADDR_BY_NAME(inst, goen),   \
239 	.reg_ksi_kso_gctrl = (uint8_t *)DT_INST_REG_ADDR_BY_NAME(inst, gctrl), \
240 	.reg_ksi_kso_gdat = (uint8_t *)DT_INST_REG_ADDR_BY_NAME(inst, gdat),   \
241 	.reg_ksi_kso_gdmr = (uint8_t *)DT_INST_REG_ADDR_BY_NAME(inst, gdmr),   \
242 	.reg_ksi_kso_gpod = (uint8_t *)DT_INST_REG_ADDR_BY_NAME(inst, gpod),   \
243 };                                                                             \
244 									       \
245 static struct gpio_kscan_data gpio_kscan_it8xxx2_data_##inst;                  \
246 									       \
247 DEVICE_DT_INST_DEFINE(inst,                                                    \
248 		      NULL,                                                    \
249 		      NULL,                                                    \
250 		      &gpio_kscan_it8xxx2_data_##inst,                         \
251 		      &gpio_kscan_it8xxx2_cfg_##inst,                          \
252 		      PRE_KERNEL_1,                                            \
253 		      CONFIG_GPIO_INIT_PRIORITY,                               \
254 		      &gpio_kscan_it8xxx2_driver_api);
255 
256 DT_INST_FOREACH_STATUS_OKAY(GPIO_KSCAN_IT8XXX2_INIT)
257