diff --git a/app/module/drivers/kscan/kscan_gpio_charlieplex.c b/app/module/drivers/kscan/kscan_gpio_charlieplex.c index 3ecbcd6a0e16..f48a6a2f40c6 100644 --- a/app/module/drivers/kscan/kscan_gpio_charlieplex.c +++ b/app/module/drivers/kscan/kscan_gpio_charlieplex.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -167,6 +168,21 @@ static int kscan_charlieplex_set_all_outputs(const struct device *dev, const int return 0; } +static int kscan_charlieplex_disconnect_all(const struct device *dev) { + const struct kscan_charlieplex_config *config = dev->config; + + for (int i = 0; i < config->cells.len; i++) { + const struct gpio_dt_spec *gpio = &config->cells.gpios[i]; + int err = gpio_pin_configure_dt(gpio, GPIO_DISCONNECTED); + if (err) { + LOG_ERR("Unable to configure pin %u on %s for input", gpio->pin, gpio->port->name); + return err; + } + } + + return 0; +} + static int kscan_charlieplex_interrupt_configure(const struct device *dev, const gpio_flags_t flags) { const struct kscan_charlieplex_config *config = dev->config; @@ -359,11 +375,7 @@ static int kscan_charlieplex_init_interrupt(const struct device *dev) { return err; } -static int kscan_charlieplex_init(const struct device *dev) { - struct kscan_charlieplex_data *data = dev->data; - - data->dev = dev; - +static void kscan_charlieplex_setup_pins(const struct device *dev) { kscan_charlieplex_init_inputs(dev); kscan_charlieplex_set_all_outputs(dev, 0); @@ -371,7 +383,46 @@ static int kscan_charlieplex_init(const struct device *dev) { if (config->use_interrupt) { kscan_charlieplex_init_interrupt(dev); } +} + +#if IS_ENABLED(CONFIG_PM_DEVICE) + +static int kscan_charlieplex_pm_action(const struct device *dev, enum pm_device_action action) { + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + kscan_charlieplex_interrupt_configure(dev, GPIO_INT_DISABLE); + kscan_charlieplex_disconnect_all(dev); + + return kscan_charlieplex_disable(dev); + case PM_DEVICE_ACTION_RESUME: + kscan_charlieplex_setup_pins(dev); + + return kscan_charlieplex_enable(dev); + default: + return -ENOTSUP; + } +} + +#endif // IS_ENABLED(CONFIG_PM_DEVICE) + +static int kscan_charlieplex_init(const struct device *dev) { + struct kscan_charlieplex_data *data = dev->data; + + data->dev = dev; + k_work_init_delayable(&data->work, kscan_charlieplex_work_handler); + +#if IS_ENABLED(CONFIG_PM_DEVICE) + pm_device_init_suspended(dev); + +#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) + pm_device_runtime_enable(dev); +#endif + +#else + kscan_charlieplex_setup_pins(dev); +#endif + return 0; } @@ -406,8 +457,10 @@ static const struct kscan_driver_api kscan_charlieplex_api = { COND_THIS_INTERRUPT(n, (.use_interrupt = INST_INTR_DEFINED(n), )) \ COND_THIS_INTERRUPT(n, (.interrupt = KSCAN_INTR_CFG_INIT(n), ))}; \ \ - DEVICE_DT_INST_DEFINE(n, &kscan_charlieplex_init, NULL, &kscan_charlieplex_data_##n, \ - &kscan_charlieplex_config_##n, POST_KERNEL, CONFIG_KSCAN_INIT_PRIORITY, \ - &kscan_charlieplex_api); + PM_DEVICE_DT_INST_DEFINE(n, kscan_charlieplex_pm_action); \ + \ + DEVICE_DT_INST_DEFINE(n, &kscan_charlieplex_init, PM_DEVICE_DT_INST_GET(n), \ + &kscan_charlieplex_data_##n, &kscan_charlieplex_config_##n, POST_KERNEL, \ + CONFIG_KSCAN_INIT_PRIORITY, &kscan_charlieplex_api); DT_INST_FOREACH_STATUS_OKAY(KSCAN_CHARLIEPLEX_INIT); diff --git a/app/module/drivers/kscan/kscan_gpio_direct.c b/app/module/drivers/kscan/kscan_gpio_direct.c index fa24e69e8956..245e78b50ccb 100644 --- a/app/module/drivers/kscan/kscan_gpio_direct.c +++ b/app/module/drivers/kscan/kscan_gpio_direct.c @@ -294,6 +294,24 @@ static int kscan_direct_init_input_inst(const struct device *dev, const struct g return 0; } +#if IS_ENABLED(CONFIG_PM_DEVICE) + +static int kscan_direct_disconnect_inputs(const struct device *dev) { + const struct kscan_direct_data *data = dev->data; + + for (int i = 0; i < data->inputs.len; i++) { + const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec; + int err = gpio_pin_configure_dt(gpio, GPIO_DISCONNECTED); + if (err) { + return err; + } + } + + return 0; +} + +#endif // IS_ENABLED(CONFIG_PM_DEVICE) + static int kscan_direct_init_inputs(const struct device *dev) { const struct kscan_direct_data *data = dev->data; const struct kscan_direct_config *config = dev->config; @@ -317,9 +335,20 @@ static int kscan_direct_init(const struct device *dev) { // Sort inputs by port so we can read each port just once per scan. kscan_gpio_list_sort_by_port(&data->inputs); + k_work_init_delayable(&data->work, kscan_direct_work_handler); + +#if IS_ENABLED(CONFIG_PM_DEVICE) + pm_device_init_suspended(dev); + +#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) + pm_device_runtime_enable(dev); +#endif + +#else + kscan_direct_init_inputs(dev); - k_work_init_delayable(&data->work, kscan_direct_work_handler); +#endif return 0; } @@ -329,8 +358,10 @@ static int kscan_direct_init(const struct device *dev) { static int kscan_direct_pm_action(const struct device *dev, enum pm_device_action action) { switch (action) { case PM_DEVICE_ACTION_SUSPEND: + kscan_direct_disconnect_inputs(dev); return kscan_direct_disable(dev); case PM_DEVICE_ACTION_RESUME: + kscan_direct_init_inputs(dev); return kscan_direct_enable(dev); default: return -ENOTSUP; diff --git a/app/module/drivers/kscan/kscan_gpio_matrix.c b/app/module/drivers/kscan/kscan_gpio_matrix.c index 8a3c39f2ba9a..e0c76395f636 100644 --- a/app/module/drivers/kscan/kscan_gpio_matrix.c +++ b/app/module/drivers/kscan/kscan_gpio_matrix.c @@ -405,6 +405,44 @@ static int kscan_matrix_init_outputs(const struct device *dev) { return 0; } +#if IS_ENABLED(CONFIG_PM_DEVICE) + +static int kscan_matrix_disconnect_inputs(const struct device *dev) { + const struct kscan_matrix_data *data = dev->data; + + for (int i = 0; i < data->inputs.len; i++) { + const struct gpio_dt_spec *gpio = &data->inputs.gpios[i].spec; + int err = gpio_pin_configure_dt(gpio, GPIO_DISCONNECTED); + if (err) { + return err; + } + } + + return 0; +} + +static int kscan_matrix_disconnect_outputs(const struct device *dev) { + const struct kscan_matrix_config *config = dev->config; + + for (int i = 0; i < config->outputs.len; i++) { + const struct gpio_dt_spec *gpio = &config->outputs.gpios[i].spec; + int err = gpio_pin_configure_dt(gpio, GPIO_DISCONNECTED); + if (err) { + return err; + } + } + + return 0; +} + +#endif // IS_ENABLED(CONFIG_PM_DEVICE) + +static void kscan_matrix_setup_pins(const struct device *dev) { + kscan_matrix_init_inputs(dev); + kscan_matrix_init_outputs(dev); + kscan_matrix_set_all_outputs(dev, 0); +} + static int kscan_matrix_init(const struct device *dev) { struct kscan_matrix_data *data = dev->data; @@ -413,12 +451,19 @@ static int kscan_matrix_init(const struct device *dev) { // Sort inputs by port so we can read each port just once per scan. kscan_gpio_list_sort_by_port(&data->inputs); - kscan_matrix_init_inputs(dev); - kscan_matrix_init_outputs(dev); - kscan_matrix_set_all_outputs(dev, 0); - k_work_init_delayable(&data->work, kscan_matrix_work_handler); +#if IS_ENABLED(CONFIG_PM_DEVICE) + pm_device_init_suspended(dev); + +#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) + pm_device_runtime_enable(dev); +#endif + +#else + kscan_matrix_setup_pins(dev); +#endif + return 0; } @@ -427,8 +472,12 @@ static int kscan_matrix_init(const struct device *dev) { static int kscan_matrix_pm_action(const struct device *dev, enum pm_device_action action) { switch (action) { case PM_DEVICE_ACTION_SUSPEND: + kscan_matrix_disconnect_inputs(dev); + kscan_matrix_disconnect_outputs(dev); + return kscan_matrix_disable(dev); case PM_DEVICE_ACTION_RESUME: + kscan_matrix_setup_pins(dev); return kscan_matrix_enable(dev); default: return -ENOTSUP; diff --git a/app/src/kscan_sideband_behaviors.c b/app/src/kscan_sideband_behaviors.c index f3992ebc5128..16d39398649e 100644 --- a/app/src/kscan_sideband_behaviors.c +++ b/app/src/kscan_sideband_behaviors.c @@ -109,15 +109,32 @@ static int ksbb_configure(const struct device *dev, kscan_callback_t callback) { static int ksbb_enable(const struct device *dev) { struct ksbb_data *data = dev->data; + const struct ksbb_config *config = dev->config; data->enabled = true; +#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) + if (!pm_device_runtime_is_enabled(dev) && pm_device_runtime_is_enabled(config->kscan)) { + pm_device_runtime_get(config->kscan); + } +#elif IS_ENABLED(CONFIG_PM_DEVICE) + pm_device_action_run(config->kscan, PM_DEVICE_ACTION_RESUME); +#endif // IS_ENABLED(CONFIG_PM_DEVICE) + return 0; } static int ksbb_disable(const struct device *dev) { struct ksbb_data *data = dev->data; + const struct ksbb_config *config = dev->config; data->enabled = false; +#if IS_ENABLED(CONFIG_PM_DEVICE_RUNTIME) + if (!pm_device_runtime_is_enabled(dev) && pm_device_runtime_is_enabled(config->kscan)) { + pm_device_runtime_put(config->kscan); + } +#elif IS_ENABLED(CONFIG_PM_DEVICE) + pm_device_action_run(config->kscan, PM_DEVICE_ACTION_SUSPEND); +#endif // IS_ENABLED(CONFIG_PM_DEVICE) return 0; } @@ -132,6 +149,8 @@ static int ksbb_init(const struct device *dev) { kscan_config(config->kscan, &ksbb_inner_kscan_callback); kscan_enable_callback(config->kscan); + ksbb_enable(dev); + return 0; } @@ -148,7 +167,7 @@ static int ksbb_pm_action(const struct device *dev, enum pm_device_action action case PM_DEVICE_ACTION_SUSPEND: return ksbb_disable(dev); case PM_DEVICE_ACTION_RESUME: - return ksbb_disable(dev); + return ksbb_enable(dev); default: return -ENOTSUP; }