diff --git a/drivers/input/CMakeLists.txt b/drivers/input/CMakeLists.txt index cab9dcd3cac..054c04ff60c 100644 --- a/drivers/input/CMakeLists.txt +++ b/drivers/input/CMakeLists.txt @@ -23,6 +23,7 @@ zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT51XXX_KBD input_ite_it51xxx_kbd. zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8801_KBD input_ite_it8801_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_ITE_IT8XXX2_KBD input_ite_it8xxx2_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_KBD_MATRIX input_kbd_matrix.c) +zephyr_library_sources_ifdef(CONFIG_INPUT_MODULINO_BUTTONS input_modulino_buttons.c) zephyr_library_sources_ifdef(CONFIG_INPUT_NPCX_KBD input_npcx_kbd.c) zephyr_library_sources_ifdef(CONFIG_INPUT_NUNCHUK input_nunchuk.c) zephyr_library_sources_ifdef(CONFIG_INPUT_PAT912X input_pat912x.c) diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index d23b1db9bed..b8dc0890b56 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -25,6 +25,7 @@ source "drivers/input/Kconfig.it51xxx" source "drivers/input/Kconfig.it8801" source "drivers/input/Kconfig.it8xxx2" source "drivers/input/Kconfig.kbd_matrix" +source "drivers/input/Kconfig.modulino" source "drivers/input/Kconfig.npcx" source "drivers/input/Kconfig.nunchuk" source "drivers/input/Kconfig.pat912x" diff --git a/drivers/input/Kconfig.modulino b/drivers/input/Kconfig.modulino new file mode 100644 index 00000000000..95ae6fe4dfd --- /dev/null +++ b/drivers/input/Kconfig.modulino @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Google, LLC +# SPDX-License-Identifier: Apache-2.0 + +config INPUT_MODULINO_BUTTONS + bool "Arduino Modulino buttons" + default y + depends on DT_HAS_ARDUINO_MODULINO_BUTTONS_ENABLED + select I2C + help + Enable driver Arduino Modulino Buttons. diff --git a/drivers/input/input_modulino_buttons.c b/drivers/input/input_modulino_buttons.c new file mode 100644 index 00000000000..d88aeff9c9c --- /dev/null +++ b/drivers/input/input_modulino_buttons.c @@ -0,0 +1,97 @@ +/* + * Copyright 2025 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT arduino_modulino_buttons + +#include +#include +#include +#include +#include + +LOG_MODULE_REGISTER(modulino_buttons, CONFIG_INPUT_LOG_LEVEL); + +#define MODULINO_NUM_BUTTONS 3 + +struct modulino_buttons_config { + struct i2c_dt_spec bus; + uint32_t poll_period_ms; + uint32_t zephyr_code[MODULINO_NUM_BUTTONS]; +}; + +struct modulino_buttons_data { + const struct device *dev; + struct k_work_delayable poll_work; + uint8_t prev_state[MODULINO_NUM_BUTTONS]; +}; + +static void modulino_buttons_handler(struct k_work *work) +{ + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct modulino_buttons_data *data = CONTAINER_OF( + dwork, struct modulino_buttons_data, poll_work); + const struct device *dev = data->dev; + const struct modulino_buttons_config *cfg = dev->config; + int ret; + uint8_t buf[MODULINO_NUM_BUTTONS + 1]; + + ret = i2c_read_dt(&cfg->bus, buf, sizeof(buf)); + if (ret < 0) { + LOG_ERR("i2c read error: %d", ret); + goto out; + } + + for (uint8_t i = 0; i < MODULINO_NUM_BUTTONS; i++) { + uint8_t state = buf[i + 1]; + + if (data->prev_state[i] != state) { + input_report_key(dev, cfg->zephyr_code[i], state, true, K_FOREVER); + } + } + + memcpy(data->prev_state, &buf[1], sizeof(data->prev_state)); + +out: + k_work_reschedule(dwork, K_MSEC(cfg->poll_period_ms)); +} + +static int modulino_buttons_init(const struct device *dev) +{ + const struct modulino_buttons_config *cfg = dev->config; + struct modulino_buttons_data *data = dev->data; + + data->dev = dev; + + if (!i2c_is_ready_dt(&cfg->bus)) { + LOG_ERR("Bus device is not ready"); + return -ENODEV; + } + + k_work_init_delayable(&data->poll_work, modulino_buttons_handler); + k_work_reschedule(&data->poll_work, K_MSEC(cfg->poll_period_ms)); + + return 0; +} + +#define MODULINO_BUTTONS_INIT(inst) \ + BUILD_ASSERT(DT_INST_PROP_LEN(inst, zephyr_codes) == MODULINO_NUM_BUTTONS, \ + "zephyr,codes must specify three key codes"); \ + \ + static const struct modulino_buttons_config modulino_buttons_cfg_##inst = { \ + .bus = I2C_DT_SPEC_GET(DT_INST_PARENT(inst)), \ + .poll_period_ms = DT_INST_PROP(inst, poll_period_ms), \ + .zephyr_code = DT_INST_PROP(inst, zephyr_codes), \ + }; \ + \ + static struct modulino_buttons_data modulino_buttons_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, modulino_buttons_init, NULL, \ + &modulino_buttons_data_##inst, \ + &modulino_buttons_cfg_##inst, \ + POST_KERNEL, CONFIG_INPUT_INIT_PRIORITY, NULL); + + +DT_INST_FOREACH_STATUS_OKAY(MODULINO_BUTTONS_INIT) diff --git a/dts/bindings/input/arduino,modulino-buttons.yaml b/dts/bindings/input/arduino,modulino-buttons.yaml new file mode 100644 index 00000000000..76215942768 --- /dev/null +++ b/dts/bindings/input/arduino,modulino-buttons.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2025 Google, LLC +# SPDX-License-Identifier: Apache-2.0 + +description: Arduino Modulino buttons + +compatible: "arduino,modulino-buttons" + +properties: + zephyr,codes: + type: array + required: true + description: | + Key codes to emit, the module has three buttons so this must specify + three key codes. + + poll-period-ms: + type: int + default: 50 + description: | + How often to poll the buttons over the i2c bus, defaults to 50ms.