1 /*
2  * Copyright (c) 2021 ITE Corporation. All Rights Reserved.
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT ite_it8xxx2_kbd
7 
8 #include <errno.h>
9 #include <soc.h>
10 #include <soc_dt.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/gpio.h>
13 #include <zephyr/drivers/interrupt_controller/wuc_ite_it8xxx2.h>
14 #include <zephyr/drivers/pinctrl.h>
15 #include <zephyr/dt-bindings/interrupt-controller/it8xxx2-wuc.h>
16 #include <zephyr/input/input.h>
17 #include <zephyr/input/input_kbd_matrix.h>
18 #include <zephyr/kernel.h>
19 #include <zephyr/sys/util_macro.h>
20 
21 #include <zephyr/logging/log.h>
22 LOG_MODULE_REGISTER(input_ite_it8xxx2_kbd);
23 
24 #define KEYBOARD_KSI_PIN_COUNT IT8XXX2_DT_INST_WUCCTRL_LEN(0)
25 
26 struct it8xxx2_kbd_wuc_map_cfg {
27 	/* WUC control device structure */
28 	const struct device *wucs;
29 	/* WUC pin mask */
30 	uint8_t mask;
31 };
32 
33 struct it8xxx2_kbd_config {
34 	struct input_kbd_matrix_common_config common;
35 	/* Keyboard scan controller base address */
36 	struct kscan_it8xxx2_regs *base;
37 	/* Keyboard scan input (KSI) wake-up irq */
38 	int irq;
39 	/* KSI[7:0] wake-up input source configuration list */
40 	const struct it8xxx2_kbd_wuc_map_cfg *wuc_map_list;
41 	/* KSI[7:0]/KSO[17:0] keyboard scan alternate configuration */
42 	const struct pinctrl_dev_config *pcfg;
43 	/* KSO16 GPIO cells */
44 	struct gpio_dt_spec kso16_gpios;
45 	/* KSO17 GPIO cells */
46 	struct gpio_dt_spec kso17_gpios;
47 	/* Mask of signals to ignore */
48 	uint32_t kso_ignore_mask;
49 };
50 
51 struct it8xxx2_kbd_data {
52 	struct input_kbd_matrix_common_data common;
53 	/* KSI[7:0] wake-up interrupt status mask */
54 	uint8_t ksi_pin_mask;
55 };
56 
57 INPUT_KBD_STRUCT_CHECK(struct it8xxx2_kbd_config, struct it8xxx2_kbd_data);
58 
it8xxx2_kbd_drive_column(const struct device * dev,int col)59 static void it8xxx2_kbd_drive_column(const struct device *dev, int col)
60 {
61 	const struct it8xxx2_kbd_config *const config = dev->config;
62 	const struct input_kbd_matrix_common_config *common = &config->common;
63 	struct kscan_it8xxx2_regs *const inst = config->base;
64 	const uint32_t kso_mask = BIT_MASK(common->col_size) & ~config->kso_ignore_mask;
65 	const uint8_t ksol_mask = kso_mask & 0xff;
66 	const uint8_t ksoh1_mask = (kso_mask >> 8) & 0xff;
67 	uint32_t kso_val;
68 	unsigned int key;
69 
70 	/* Tri-state all outputs */
71 	if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) {
72 		kso_val = kso_mask;
73 	/* Assert all outputs */
74 	} else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) {
75 		kso_val = 0;
76 	/* Assert a single output */
77 	} else {
78 		kso_val = kso_mask ^ BIT(col);
79 	}
80 
81 	/* Set KSO[17:0] output data, disable global interrupts for critical section.
82 	 * The KBS_KSO* registers contains both keyboard and GPIO output settings.
83 	 * Not all bits are for the keyboard will be driven, so a critical section
84 	 * is needed to avoid race conditions.
85 	 */
86 	key = irq_lock();
87 	inst->KBS_KSOL = (inst->KBS_KSOL & ~ksol_mask) | (kso_val & ksol_mask);
88 	inst->KBS_KSOH1 = (inst->KBS_KSOH1 & ~ksoh1_mask) | ((kso_val >> 8) & ksoh1_mask);
89 	irq_unlock(key);
90 
91 	if (common->col_size > 16) {
92 		inst->KBS_KSOH2 = (kso_val >> 16) & 0xff;
93 	}
94 }
95 
it8xxx2_kbd_read_row(const struct device * dev)96 static kbd_row_t it8xxx2_kbd_read_row(const struct device *dev)
97 {
98 	const struct it8xxx2_kbd_config *const config = dev->config;
99 	struct kscan_it8xxx2_regs *const inst = config->base;
100 
101 	/* Bits are active-low, so toggle it (return 1 means key pressed) */
102 	return (inst->KBS_KSI ^ 0xff);
103 }
104 
it8xxx2_kbd_isr(const struct device * dev)105 static void it8xxx2_kbd_isr(const struct device *dev)
106 {
107 	const struct it8xxx2_kbd_config *const config = dev->config;
108 	struct it8xxx2_kbd_data *data = dev->data;
109 
110 	/*
111 	 * W/C wakeup interrupt status of KSI[7:0] pins
112 	 *
113 	 * NOTE: We want to clear the status as soon as possible,
114 	 *       so clear KSI[7:0] pins at a time.
115 	 */
116 	it8xxx2_wuc_clear_status(config->wuc_map_list[0].wucs,
117 				 data->ksi_pin_mask);
118 
119 	/* W/C interrupt status of KSI[7:0] pins */
120 	ite_intc_isr_clear(config->irq);
121 
122 	input_kbd_matrix_poll_start(dev);
123 }
124 
it8xxx2_kbd_set_detect_mode(const struct device * dev,bool enable)125 static void it8xxx2_kbd_set_detect_mode(const struct device *dev, bool enable)
126 {
127 	const struct it8xxx2_kbd_config *const config = dev->config;
128 	struct it8xxx2_kbd_data *data = dev->data;
129 
130 	if (enable) {
131 		/*
132 		 * W/C wakeup interrupt status of KSI[7:0] pins
133 		 *
134 		 * NOTE: We want to clear the status as soon as possible,
135 		 *       so clear KSI[7:0] pins at a time.
136 		 */
137 		it8xxx2_wuc_clear_status(config->wuc_map_list[0].wucs,
138 					 data->ksi_pin_mask);
139 
140 		/* W/C interrupt status of KSI[7:0] pins */
141 		ite_intc_isr_clear(config->irq);
142 
143 		irq_enable(config->irq);
144 	} else {
145 		irq_disable(config->irq);
146 	}
147 }
148 
it8xxx2_kbd_init(const struct device * dev)149 static int it8xxx2_kbd_init(const struct device *dev)
150 {
151 	const struct it8xxx2_kbd_config *const config = dev->config;
152 	const struct input_kbd_matrix_common_config *common = &config->common;
153 	struct it8xxx2_kbd_data *data = dev->data;
154 	struct kscan_it8xxx2_regs *const inst = config->base;
155 	const uint32_t kso_mask = BIT_MASK(common->col_size) & ~config->kso_ignore_mask;
156 	const uint8_t ksol_mask = kso_mask & 0xff;
157 	const uint8_t ksoh1_mask = (kso_mask >> 8) & 0xff;
158 	int status;
159 
160 	/* Disable wakeup and interrupt of KSI pins before configuring */
161 	it8xxx2_kbd_set_detect_mode(dev, false);
162 
163 	if (common->col_size > 16) {
164 		/*
165 		 * For KSO[16] and KSO[17]:
166 		 * 1.GPOTRC:
167 		 *   Bit[x] = 1b: Enable the open-drain mode of KSO pin
168 		 * 2.GPCRCx:
169 		 *   Bit[7:6] = 00b: Select alternate KSO function
170 		 *   Bit[2] = 1b: Enable the internal pull-up of KSO pin
171 		 *
172 		 * NOTE: Set input temporarily for gpio_pin_configure(), after
173 		 * that pinctrl_apply_state() set to alternate function
174 		 * immediately.
175 		 */
176 		gpio_pin_configure_dt(&config->kso16_gpios, GPIO_INPUT);
177 		gpio_pin_configure_dt(&config->kso17_gpios, GPIO_INPUT);
178 	}
179 	/*
180 	 * Enable the internal pull-up and kbs mode of the KSI[7:0] pins.
181 	 * Enable the internal pull-up and kbs mode of the KSO[15:0] pins.
182 	 * Enable the open-drain mode of the KSO[17:0] pins.
183 	 */
184 	status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
185 	if (status < 0) {
186 		LOG_ERR("Failed to configure KSI[7:0] and KSO[17:0] pins");
187 		return status;
188 	}
189 
190 	/* KSO[17:0] pins output low */
191 	inst->KBS_KSOL = inst->KBS_KSOL & ~ksol_mask;
192 	inst->KBS_KSOH1 = inst->KBS_KSOH1 & ~ksoh1_mask;
193 	if (common->col_size > 16) {
194 		inst->KBS_KSOH2 = 0x00;
195 	}
196 
197 	for (int i = 0; i < KEYBOARD_KSI_PIN_COUNT; i++) {
198 		/* Select wakeup interrupt falling-edge triggered of KSI[7:0] pins */
199 		it8xxx2_wuc_set_polarity(config->wuc_map_list[i].wucs,
200 					 config->wuc_map_list[i].mask,
201 					 WUC_TYPE_EDGE_FALLING);
202 		/* W/C wakeup interrupt status of KSI[7:0] pins */
203 		it8xxx2_wuc_clear_status(config->wuc_map_list[i].wucs,
204 					 config->wuc_map_list[i].mask);
205 		/* Enable wakeup interrupt of KSI[7:0] pins */
206 		it8xxx2_wuc_enable(config->wuc_map_list[i].wucs,
207 				   config->wuc_map_list[i].mask);
208 
209 		/*
210 		 * We want to clear KSI[7:0] pins status at a time when wakeup
211 		 * interrupt fire, so gather the KSI[7:0] pin mask value here.
212 		 */
213 		if (config->wuc_map_list[i].wucs != config->wuc_map_list[0].wucs) {
214 			LOG_ERR("KSI%d pin isn't in the same wuc node!", i);
215 		}
216 		data->ksi_pin_mask |= config->wuc_map_list[i].mask;
217 	}
218 
219 	/* W/C interrupt status of KSI[7:0] pins */
220 	ite_intc_isr_clear(config->irq);
221 
222 	irq_connect_dynamic(DT_INST_IRQN(0), 0,
223 			    (void (*)(const void *))it8xxx2_kbd_isr,
224 			    (const void *)dev, 0);
225 
226 	return input_kbd_matrix_common_init(dev);
227 }
228 
229 static const struct it8xxx2_kbd_wuc_map_cfg
230 	it8xxx2_kbd_wuc[IT8XXX2_DT_INST_WUCCTRL_LEN(0)] = IT8XXX2_DT_WUC_ITEMS_LIST(0);
231 
232 PINCTRL_DT_INST_DEFINE(0);
233 
234 INPUT_KBD_MATRIX_DT_INST_DEFINE(0);
235 
236 static const struct input_kbd_matrix_api it8xxx2_kbd_api = {
237 	.drive_column = it8xxx2_kbd_drive_column,
238 	.read_row = it8xxx2_kbd_read_row,
239 	.set_detect_mode = it8xxx2_kbd_set_detect_mode,
240 };
241 
242 static const struct it8xxx2_kbd_config it8xxx2_kbd_cfg_0 = {
243 	.common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(0, &it8xxx2_kbd_api),
244 	.base = (struct kscan_it8xxx2_regs *)DT_INST_REG_ADDR_BY_IDX(0, 0),
245 	.irq = DT_INST_IRQN(0),
246 	.wuc_map_list = it8xxx2_kbd_wuc,
247 	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
248 	.kso16_gpios = GPIO_DT_SPEC_INST_GET(0, kso16_gpios),
249 	.kso17_gpios = GPIO_DT_SPEC_INST_GET(0, kso17_gpios),
250 	.kso_ignore_mask = DT_INST_PROP(0, kso_ignore_mask),
251 };
252 
253 static struct it8xxx2_kbd_data it8xxx2_kbd_data_0;
254 
255 PM_DEVICE_DT_INST_DEFINE(0, input_kbd_matrix_pm_action);
256 
257 DEVICE_DT_INST_DEFINE(0, &it8xxx2_kbd_init, PM_DEVICE_DT_INST_GET(0),
258 		      &it8xxx2_kbd_data_0, &it8xxx2_kbd_cfg_0,
259 		      POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);
260 
261 BUILD_ASSERT(!IS_ENABLED(CONFIG_PM_DEVICE_SYSTEM_MANAGED) ||
262 	     IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME),
263 	     "CONFIG_PM_DEVICE_RUNTIME must be enabled when using CONFIG_PM_DEVICE_SYSTEM_MANAGED");
264 
265 BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
266 	     "only one ite,it8xxx2-kbd compatible node can be supported");
267 BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, row_size), 1, 8), "invalid row-size");
268 BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, col_size), 1, 18), "invalid col-size");
269