Skip to content

Commit 2441e76

Browse files
mcuxtedkartben
authored andcommitted
driver: input: Add support for KPP driver.
Added support for KPP driver. Signed-off-by: Qiang Zhang <[email protected]>
1 parent 0887ccd commit 2441e76

File tree

4 files changed

+209
-0
lines changed

4 files changed

+209
-0
lines changed

drivers/input/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT51XXX_KBD input_ite_it51xxx_kbd.
2424
zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8801_KBD input_ite_it8801_kbd.c)
2525
zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8XXX2_KBD input_ite_it8xxx2_kbd.c)
2626
zephyr_library_sources_ifdef(CONFIG_INPUT_KBD_MATRIX input_kbd_matrix.c)
27+
zephyr_library_sources_ifdef(CONFIG_INPUT_MCUX_KPP input_mcux_kpp.c)
2728
zephyr_library_sources_ifdef(CONFIG_INPUT_MODULINO_BUTTONS input_modulino_buttons.c)
2829
zephyr_library_sources_ifdef(CONFIG_INPUT_NPCX_KBD input_npcx_kbd.c)
2930
zephyr_library_sources_ifdef(CONFIG_INPUT_NUNCHUK input_nunchuk.c)

drivers/input/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ source "drivers/input/Kconfig.it51xxx"
2626
source "drivers/input/Kconfig.it8801"
2727
source "drivers/input/Kconfig.it8xxx2"
2828
source "drivers/input/Kconfig.kbd_matrix"
29+
source "drivers/input/Kconfig.mcux_kpp"
2930
source "drivers/input/Kconfig.modulino"
3031
source "drivers/input/Kconfig.npcx"
3132
source "drivers/input/Kconfig.nunchuk"

drivers/input/Kconfig.mcux_kpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config INPUT_MCUX_KPP
5+
bool "KPP driver"
6+
default y
7+
depends on DT_HAS_NXP_MCUX_KPP_ENABLED
8+
help
9+
Enable the driver of keypad port.
10+
11+
config INPUT_KPP_PERIOD_MS
12+
int "Sample period"
13+
default 10
14+
depends on INPUT_MCUX_KPP
15+
help
16+
Sample period in milliseconds when the key is pressed.

drivers/input/input_mcux_kpp.c

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright 2025, NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/kernel.h>
8+
#include <zephyr/device.h>
9+
#include <zephyr/input/input.h>
10+
#include <zephyr/logging/log.h>
11+
#include <fsl_kpp.h>
12+
#include <zephyr/drivers/clock_control.h>
13+
#include <zephyr/dt-bindings/clock/imx_ccm.h>
14+
#include <zephyr/drivers/pinctrl.h>
15+
#include <zephyr/sys/util.h>
16+
17+
LOG_MODULE_REGISTER(kpp, CONFIG_INPUT_LOG_LEVEL);
18+
19+
#define DT_DRV_COMPAT nxp_mcux_kpp
20+
21+
#define INPUT_KPP_COLUMNNUM_MAX KPP_KEYPAD_COLUMNNUM_MAX
22+
#define INPUT_KPP_ROWNUM_MAX KPP_KEYPAD_ROWNUM_MAX
23+
#define INPUT_KPP_ROWNUM_MAX KPP_KEYPAD_ROWNUM_MAX
24+
25+
struct kpp_config {
26+
KPP_Type *base;
27+
const struct device *ccm_dev;
28+
clock_control_subsys_t clk_sub_sys;
29+
const struct pinctrl_dev_config *pcfg;
30+
};
31+
32+
struct kpp_data {
33+
uint32_t clock_rate;
34+
struct k_work_delayable work;
35+
uint8_t read_keys_old[KPP_KEYPAD_COLUMNNUM_MAX];
36+
uint8_t read_keys_new[KPP_KEYPAD_COLUMNNUM_MAX];
37+
uint8_t key_pressed_number;
38+
const struct device *dev;
39+
};
40+
41+
static void get_source_clk_rate(const struct device *dev, uint32_t *clk_rate)
42+
{
43+
const struct kpp_config *dev_cfg = dev->config;
44+
const struct device *ccm_dev = dev_cfg->ccm_dev;
45+
clock_control_subsys_t clk_sub_sys = dev_cfg->clk_sub_sys;
46+
47+
if (!device_is_ready(ccm_dev)) {
48+
LOG_ERR("CCM driver is not installed");
49+
*clk_rate = 0;
50+
return;
51+
}
52+
53+
clock_control_get_rate(ccm_dev, clk_sub_sys, clk_rate);
54+
}
55+
56+
static void kpp_work_handler(struct k_work *work)
57+
{
58+
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
59+
struct kpp_data *drv_data = CONTAINER_OF(dwork, struct kpp_data, work);
60+
const struct device *dev = drv_data->dev;
61+
const struct kpp_config *config = dev->config;
62+
63+
uint8_t read_keys_new[KPP_KEYPAD_COLUMNNUM_MAX];
64+
65+
/* Read the key press data */
66+
KPP_keyPressScanning(config->base, read_keys_new, drv_data->clock_rate);
67+
68+
/* Analyze the keypad data */
69+
for (int col = 0; col < INPUT_KPP_COLUMNNUM_MAX; col++) {
70+
if (drv_data->read_keys_old[col] == read_keys_new[col]) {
71+
continue;
72+
}
73+
for (int row = 0; row < INPUT_KPP_ROWNUM_MAX; row++) {
74+
if (((drv_data->read_keys_old[col] ^ read_keys_new[col])
75+
& BIT(row)) == 0) {
76+
continue;
77+
}
78+
if ((read_keys_new[col] & BIT(row)) != 0) {
79+
/* Key press event */
80+
KPP_SetSynchronizeChain(config->base,
81+
kKPP_ClearKeyDepressSyncChain);
82+
input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER);
83+
input_report_abs(dev, INPUT_ABS_Y, row, false, K_FOREVER);
84+
input_report_key(dev, INPUT_BTN_TOUCH, 1, true, K_FOREVER);
85+
drv_data->key_pressed_number++;
86+
} else {
87+
/* Key release event */
88+
KPP_SetSynchronizeChain(config->base,
89+
kKPP_SetKeyReleasesSyncChain);
90+
input_report_abs(dev, INPUT_ABS_X, col, false, K_FOREVER);
91+
input_report_abs(dev, INPUT_ABS_Y, row, false, K_FOREVER);
92+
input_report_key(dev, INPUT_BTN_TOUCH, 0, true, K_FOREVER);
93+
drv_data->key_pressed_number--;
94+
}
95+
drv_data->read_keys_old[col] = read_keys_new[col];
96+
}
97+
}
98+
99+
if (drv_data->key_pressed_number == 0U) {
100+
KPP_ClearStatusFlag(config->base, kKPP_keyDepressInterrupt |
101+
kKPP_keyReleaseInterrupt);
102+
KPP_EnableInterrupts(config->base, kKPP_keyDepressInterrupt);
103+
} else {
104+
k_work_schedule(&drv_data->work, K_MSEC(CONFIG_INPUT_KPP_PERIOD_MS));
105+
}
106+
}
107+
108+
static void kpp_isr(const struct device *dev)
109+
{
110+
const struct kpp_config *config = dev->config;
111+
struct kpp_data *drv_data = dev->data;
112+
113+
uint16_t status = KPP_GetStatusFlag(config->base);
114+
115+
if ((status & kKPP_keyDepressInterrupt) == 0) {
116+
LOG_ERR("No key press or release detected");
117+
return;
118+
}
119+
120+
drv_data->key_pressed_number = 0;
121+
/* Disable interrupts. */
122+
KPP_DisableInterrupts(config->base, kKPP_keyDepressInterrupt |
123+
kKPP_keyReleaseInterrupt);
124+
/* Clear status. */
125+
KPP_ClearStatusFlag(config->base, kKPP_keyDepressInterrupt |
126+
kKPP_keyReleaseInterrupt);
127+
/* Key depress report */
128+
k_work_schedule(&drv_data->work, K_MSEC(0));
129+
}
130+
131+
static int input_kpp_init(const struct device *dev)
132+
{
133+
const struct kpp_config *config = dev->config;
134+
struct kpp_data *drv_data = dev->data;
135+
kpp_config_t kppConfig;
136+
137+
if (!device_is_ready(config->ccm_dev)) {
138+
LOG_ERR("CCM driver is not installed");
139+
return -ENODEV;
140+
}
141+
142+
int ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
143+
144+
if (ret < 0) {
145+
LOG_ERR("Failed to configure pin");
146+
return ret;
147+
}
148+
149+
kppConfig.activeRow = 0xFF;
150+
kppConfig.activeColumn = 0xFF;
151+
kppConfig.interrupt = kKPP_keyDepressInterrupt;
152+
153+
KPP_Init(config->base, &kppConfig);
154+
155+
get_source_clk_rate(dev, &drv_data->clock_rate);
156+
157+
drv_data->dev = dev;
158+
159+
/* Read the key press data */
160+
KPP_keyPressScanning(config->base, drv_data->read_keys_old, drv_data->clock_rate);
161+
162+
k_work_init_delayable(&drv_data->work, kpp_work_handler);
163+
164+
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
165+
kpp_isr, DEVICE_DT_INST_GET(0), 0);
166+
return 0;
167+
}
168+
169+
#define INPUT_KPP_INIT(n) \
170+
static struct kpp_data kpp_data_##n; \
171+
\
172+
PINCTRL_DT_INST_DEFINE(n); \
173+
\
174+
static const struct kpp_config kpp_config_##n = { \
175+
.base = (KPP_Type *)DT_INST_REG_ADDR(n), \
176+
.clk_sub_sys = \
177+
(clock_control_subsys_t)DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name), \
178+
.ccm_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
179+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
180+
}; \
181+
\
182+
DEVICE_DT_INST_DEFINE(n, \
183+
input_kpp_init, \
184+
NULL, \
185+
&kpp_data_##n, \
186+
&kpp_config_##n, \
187+
POST_KERNEL, \
188+
CONFIG_INPUT_INIT_PRIORITY, \
189+
NULL);
190+
191+
DT_INST_FOREACH_STATUS_OKAY(INPUT_KPP_INIT)

0 commit comments

Comments
 (0)