Skip to content

Commit fb35b68

Browse files
RuibinChangkartben
authored andcommitted
drivers/input/it51xxx: implement kbd driver
Implement kbd driver for ITE it51xxx series chip. Signed-off-by: Ruibin Chang <Ruibin.Chang@ite.com.tw>
1 parent 72aa2a9 commit fb35b68

File tree

7 files changed

+362
-0
lines changed

7 files changed

+362
-0
lines changed

boards/ite/it515xx_evb/it515xx_evb.dts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,34 @@
7272
};
7373
};
7474
};
75+
76+
&kbd {
77+
status = "okay";
78+
pinctrl-0 = <&ksi0_default
79+
&ksi1_default
80+
&ksi2_default
81+
&ksi3_default
82+
&ksi4_default
83+
&ksi5_default
84+
&ksi6_default
85+
&ksi7_default
86+
&kso0_default
87+
&kso1_default
88+
&kso2_default
89+
&kso3_default
90+
&kso4_default
91+
&kso5_default
92+
&kso6_default
93+
&kso7_default
94+
&kso8_default
95+
&kso9_default
96+
&kso10_default
97+
&kso11_default
98+
&kso12_default
99+
&kso13_default
100+
&kso14_default
101+
&kso15_default>;
102+
pinctrl-names = "default";
103+
row-size = <8>;
104+
col-size = <16>;
105+
};

drivers/input/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_KEYS input_gpio_keys.c)
1919
zephyr_library_sources_ifdef(CONFIG_INPUT_GPIO_QDEC input_gpio_qdec.c)
2020
zephyr_library_sources_ifdef(CONFIG_INPUT_GT911 input_gt911.c)
2121
zephyr_library_sources_ifdef(CONFIG_INPUT_ILI2132A input_ili2132a.c)
22+
zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT51XXX_KBD input_ite_it51xxx_kbd.c)
2223
zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8801_KBD input_ite_it8801_kbd.c)
2324
zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8XXX2_KBD input_ite_it8xxx2_kbd.c)
2425
zephyr_library_sources_ifdef(CONFIG_INPUT_KBD_MATRIX input_kbd_matrix.c)

drivers/input/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ source "drivers/input/Kconfig.gpio_keys"
2121
source "drivers/input/Kconfig.gpio_qdec"
2222
source "drivers/input/Kconfig.gt911"
2323
source "drivers/input/Kconfig.ili2132a"
24+
source "drivers/input/Kconfig.it51xxx"
2425
source "drivers/input/Kconfig.it8801"
2526
source "drivers/input/Kconfig.it8xxx2"
2627
source "drivers/input/Kconfig.kbd_matrix"

drivers/input/Kconfig.it51xxx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) 2025 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config INPUT_ITE_IT51XXX_KBD
5+
bool "ITE keyboard scanning driver"
6+
default y
7+
depends on DT_HAS_ITE_IT51XXX_KBD_ENABLED
8+
select INPUT_KBD_MATRIX
9+
select PINCTRL
10+
help
11+
This option enables the ITE keyboard scan driver.

drivers/input/input_ite_it51xxx_kbd.c

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
* Copyright (c) 2025 ITE Corporation. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT ite_it51xxx_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_it51xxx.h>
14+
#include <zephyr/drivers/pinctrl.h>
15+
#include <zephyr/dt-bindings/interrupt-controller/ite-it51xxx-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_it51xxx_kbd);
23+
24+
#define KEYBOARD_KSI_PIN_COUNT IT8XXX2_DT_INST_WUCCTRL_LEN(0)
25+
26+
/* 0x04: Keyboard Scan In Data */
27+
#define REG_KBS_KSI 0x04
28+
/* 0x80: Keyboard Scan Out Data (3 bytes value and 4 bytes aligned) */
29+
#define REG_KBS_KSO 0x80
30+
31+
struct it51xxx_kbd_wuc_map_cfg {
32+
/* WUC control device structure */
33+
const struct device *wucs;
34+
/* WUC pin mask */
35+
uint8_t mask;
36+
};
37+
38+
struct it51xxx_kbd_config {
39+
struct input_kbd_matrix_common_config common;
40+
/* Keyboard scan controller base address */
41+
uintptr_t base;
42+
/* Keyboard scan input (KSI) wake-up irq */
43+
int irq;
44+
/* KSI[7:0] wake-up input source configuration list */
45+
const struct it51xxx_kbd_wuc_map_cfg *wuc_map_list;
46+
/* keyboard scan alternate configuration */
47+
const struct pinctrl_dev_config *pcfg;
48+
/* KSO16 GPIO cells */
49+
struct gpio_dt_spec kso16_gpios;
50+
/* KSO17 GPIO cells */
51+
struct gpio_dt_spec kso17_gpios;
52+
/* Mask of signals to ignore */
53+
uint32_t kso_ignore_mask;
54+
};
55+
56+
struct it51xxx_kbd_data {
57+
struct input_kbd_matrix_common_data common;
58+
/* KSI[7:0] wake-up interrupt status mask */
59+
uint8_t ksi_pin_mask;
60+
};
61+
62+
INPUT_KBD_STRUCT_CHECK(struct it51xxx_kbd_config, struct it51xxx_kbd_data);
63+
64+
static void it51xxx_kbd_drive_column(const struct device *dev, int col)
65+
{
66+
const struct it51xxx_kbd_config *const config = dev->config;
67+
const struct input_kbd_matrix_common_config *common = &config->common;
68+
const uintptr_t base = config->base;
69+
const uint32_t kso_mask = BIT_MASK(common->col_size) & ~config->kso_ignore_mask;
70+
uint32_t kso_val, reg_val;
71+
unsigned int key;
72+
73+
if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_NONE) {
74+
/* Tri-state all outputs */
75+
kso_val = kso_mask;
76+
} else if (col == INPUT_KBD_MATRIX_COLUMN_DRIVE_ALL) {
77+
/* Assert all outputs */
78+
kso_val = 0;
79+
} else {
80+
/* Assert a single output */
81+
kso_val = kso_mask ^ BIT(col);
82+
}
83+
84+
/*
85+
* Set keyboard scan output data, disable global interrupts for critical section.
86+
* The KBS_KSO registers contains both keyboard and GPIO output settings.
87+
* Not all bits are for the keyboard will be driven, so a critical section
88+
* is needed to avoid race conditions.
89+
*/
90+
key = irq_lock();
91+
reg_val = sys_read32(base + REG_KBS_KSO) & ~kso_mask;
92+
sys_write32((reg_val | (kso_val & kso_mask)), base + REG_KBS_KSO);
93+
irq_unlock(key);
94+
}
95+
96+
static kbd_row_t it51xxx_kbd_read_row(const struct device *dev)
97+
{
98+
const struct it51xxx_kbd_config *const config = dev->config;
99+
const uintptr_t base = config->base;
100+
uint8_t reg_val;
101+
102+
/* Bits are active-low, so toggle it (return 1 means key pressed) */
103+
reg_val = sys_read8(base + REG_KBS_KSI);
104+
105+
return reg_val ^ 0xff;
106+
}
107+
108+
static void it51xxx_kbd_clear_status(const struct device *dev)
109+
{
110+
const struct it51xxx_kbd_config *const config = dev->config;
111+
struct it51xxx_kbd_data *data = dev->data;
112+
113+
/*
114+
* W/C wakeup interrupt status of KSI[7:0] pins
115+
*
116+
* NOTE: We want to clear the status as soon as possible,
117+
* so clear KSI[7:0] pins at a time.
118+
*/
119+
it51xxx_wuc_clear_status(config->wuc_map_list[0].wucs, data->ksi_pin_mask);
120+
121+
/* W/C interrupt status of KSI[7:0] pins */
122+
ite_intc_isr_clear(config->irq);
123+
}
124+
125+
static void it51xxx_kbd_isr(const struct device *dev)
126+
{
127+
it51xxx_kbd_clear_status(dev);
128+
129+
input_kbd_matrix_poll_start(dev);
130+
}
131+
132+
static void it51xxx_kbd_set_detect_mode(const struct device *dev, bool enable)
133+
{
134+
const struct it51xxx_kbd_config *const config = dev->config;
135+
136+
if (enable) {
137+
it51xxx_kbd_clear_status(dev);
138+
139+
irq_enable(config->irq);
140+
} else {
141+
irq_disable(config->irq);
142+
}
143+
}
144+
145+
static int it51xxx_kbd_init(const struct device *dev)
146+
{
147+
const struct it51xxx_kbd_config *const config = dev->config;
148+
const struct input_kbd_matrix_common_config *common = &config->common;
149+
struct it51xxx_kbd_data *data = dev->data;
150+
const uintptr_t base = config->base;
151+
const uint32_t kso_mask = BIT_MASK(common->col_size) & ~config->kso_ignore_mask;
152+
int status;
153+
uint32_t reg_val;
154+
155+
/* Disable wakeup and interrupt of KSI pins before configuring */
156+
it51xxx_kbd_set_detect_mode(dev, false);
157+
158+
if (common->col_size > 16) {
159+
/*
160+
* For KSO[16] and KSO[17]:
161+
* Set pull up and open-drain by their GPIO ports corresponding
162+
* GPCRx and GPOTx registers.
163+
*/
164+
gpio_pin_configure_dt(&config->kso16_gpios, (GPIO_OPEN_DRAIN | GPIO_PULL_UP));
165+
gpio_pin_configure_dt(&config->kso17_gpios, (GPIO_OPEN_DRAIN | GPIO_PULL_UP));
166+
}
167+
/* Enable keyboard scan alternate function */
168+
status = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
169+
if (status < 0) {
170+
LOG_ERR("Failed to enable keyboard scan alternate function");
171+
return status;
172+
}
173+
174+
/* KSO[col_size:0] pins output low */
175+
reg_val = sys_read32(base + REG_KBS_KSO) & ~kso_mask;
176+
sys_write32(reg_val, base + REG_KBS_KSO);
177+
178+
for (int i = 0; i < KEYBOARD_KSI_PIN_COUNT; i++) {
179+
/* Select wakeup interrupt falling-edge triggered of KSI[7:0] pins */
180+
it51xxx_wuc_set_polarity(config->wuc_map_list[i].wucs, config->wuc_map_list[i].mask,
181+
WUC_TYPE_EDGE_FALLING);
182+
/* W/C wakeup interrupt status of KSI[7:0] pins */
183+
it51xxx_wuc_clear_status(config->wuc_map_list[i].wucs,
184+
config->wuc_map_list[i].mask);
185+
/* Enable wakeup interrupt of KSI[7:0] pins */
186+
it51xxx_wuc_enable(config->wuc_map_list[i].wucs, config->wuc_map_list[i].mask);
187+
188+
/*
189+
* We want to clear KSI[7:0] pins status at a time when wakeup
190+
* interrupt fire, so gather the KSI[7:0] pin mask value here.
191+
*/
192+
if (config->wuc_map_list[i].wucs != config->wuc_map_list[0].wucs) {
193+
LOG_ERR("KSI%d pin isn't in the same wuc node!", i);
194+
}
195+
data->ksi_pin_mask |= config->wuc_map_list[i].mask;
196+
}
197+
198+
/* W/C interrupt status of KSI[7:0] pins */
199+
ite_intc_isr_clear(config->irq);
200+
201+
irq_connect_dynamic(DT_INST_IRQN(0), 0, (void (*)(const void *))it51xxx_kbd_isr,
202+
(const void *)dev, 0);
203+
204+
return input_kbd_matrix_common_init(dev);
205+
}
206+
207+
static const struct it51xxx_kbd_wuc_map_cfg it51xxx_kbd_wuc[IT8XXX2_DT_INST_WUCCTRL_LEN(0)] =
208+
IT8XXX2_DT_WUC_ITEMS_LIST(0);
209+
210+
PINCTRL_DT_INST_DEFINE(0);
211+
212+
INPUT_KBD_MATRIX_DT_INST_DEFINE(0);
213+
214+
static const struct input_kbd_matrix_api it51xxx_kbd_api = {
215+
.drive_column = it51xxx_kbd_drive_column,
216+
.read_row = it51xxx_kbd_read_row,
217+
.set_detect_mode = it51xxx_kbd_set_detect_mode,
218+
};
219+
220+
static const struct it51xxx_kbd_config it51xxx_kbd_cfg_0 = {
221+
.common = INPUT_KBD_MATRIX_DT_INST_COMMON_CONFIG_INIT(0, &it51xxx_kbd_api),
222+
.base = DT_INST_REG_ADDR(0),
223+
.irq = DT_INST_IRQN(0),
224+
.wuc_map_list = it51xxx_kbd_wuc,
225+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
226+
.kso16_gpios = GPIO_DT_SPEC_INST_GET(0, kso16_gpios),
227+
.kso17_gpios = GPIO_DT_SPEC_INST_GET(0, kso17_gpios),
228+
.kso_ignore_mask = DT_INST_PROP(0, kso_ignore_mask),
229+
};
230+
231+
static struct it51xxx_kbd_data it51xxx_kbd_data_0;
232+
233+
PM_DEVICE_DT_INST_DEFINE(0, input_kbd_matrix_pm_action);
234+
235+
DEVICE_DT_INST_DEFINE(0, &it51xxx_kbd_init, PM_DEVICE_DT_INST_GET(0), &it51xxx_kbd_data_0,
236+
&it51xxx_kbd_cfg_0, POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL);
237+
238+
BUILD_ASSERT(!IS_ENABLED(CONFIG_PM_DEVICE_SYSTEM_MANAGED) || IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME),
239+
"CONFIG_PM_DEVICE_RUNTIME must be enabled when using CONFIG_PM_DEVICE_SYSTEM_MANAGED");
240+
241+
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
242+
"only one ite,it51xxx-kbd compatible node can be supported");
243+
BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, row_size), 1, 8), "invalid row-size");
244+
BUILD_ASSERT(IN_RANGE(DT_INST_PROP(0, col_size), 1, 18), "invalid col-size");
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Copyright (c) 2025 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ITE it51xxx keyboard matrix controller
5+
6+
compatible: "ite,it51xxx-kbd"
7+
8+
include: [kbd-matrix-common.yaml, pinctrl-device.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
interrupts:
15+
required: true
16+
17+
wucctrl:
18+
type: phandles
19+
description: |
20+
Configure wakeup controller, this controller is used to set that
21+
when the interrupt is triggered in EC low power mode, it can wakeup
22+
EC or not. Via this controller, we set the wakeup trigger edge,
23+
enable, disable, and clear wakeup status for the specific pin which
24+
may be gpio pins or alternate pins.
25+
26+
kso16-gpios:
27+
type: phandle-array
28+
required: true
29+
description: |
30+
The KSO16 pin for the selected port.
31+
32+
kso17-gpios:
33+
type: phandle-array
34+
required: true
35+
description: |
36+
The KSO17 pin for the selected port.
37+
38+
kso-ignore-mask:
39+
type: int
40+
default: 0
41+
description: |
42+
Bitmask of KSO signals to ignore, this can be used to instruct the driver
43+
to skip KSO signals between 0 and (col-size - 1) that are used as GPIOs.
44+
Default to 0 (no signals masked).
45+
46+
pinctrl-0:
47+
required: true
48+
49+
pinctrl-names:
50+
required: true
51+
52+
row-size:
53+
required: true
54+
55+
col-size:
56+
required: true

dts/riscv/ite/it51xxx.dtsi

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,5 +987,23 @@
987987
IT51XXX_IRQ_TIMER7_DW IRQ_TYPE_EDGE_RISING>;
988988
interrupt-parent = <&intc>;
989989
};
990+
991+
kbd: kbd@f01d00 {
992+
compatible = "ite,it51xxx-kbd";
993+
reg = <0x00f01d00 0x29>;
994+
interrupt-parent = <&intc>;
995+
interrupts = <IT51XXX_IRQ_WKINTC IRQ_TYPE_LEVEL_HIGH>;
996+
status = "disabled";
997+
wucctrl = <&wuc_wu30 /* KSI[0] */
998+
&wuc_wu31 /* KSI[1] */
999+
&wuc_wu32 /* KSI[2] */
1000+
&wuc_wu33 /* KSI[3] */
1001+
&wuc_wu34 /* KSI[4] */
1002+
&wuc_wu35 /* KSI[5] */
1003+
&wuc_wu36 /* KSI[6] */
1004+
&wuc_wu37>; /* KSI[7] */
1005+
kso16-gpios = <&gpioc 3 (GPIO_OPEN_DRAIN | GPIO_PULL_UP)>;
1006+
kso17-gpios = <&gpioc 5 (GPIO_OPEN_DRAIN | GPIO_PULL_UP)>;
1007+
};
9901008
};
9911009
};

0 commit comments

Comments
 (0)