aboutsummaryrefslogtreecommitdiffhomepage
path: root/app/module
diff options
context:
space:
mode:
authorPeter Johanson <[email protected]>2024-04-24 21:11:16 -0700
committerPete Johanson <[email protected]>2024-07-03 16:52:05 -0600
commit0438cb0ee532a31291aee3dabe24362f16146fd2 (patch)
tree77f1e815577f6b0f252ddde0dcbfae665de45fce /app/module
parentc5cca5b34f53263892257460acf681ffa490a240 (diff)
downloadzmk-0438cb0ee532a31291aee3dabe24362f16146fd2.tar.gz
zmk-0438cb0ee532a31291aee3dabe24362f16146fd2.zip
feat(kscan): More complete PM support to drivers.
* Update our GPIO kscan drivers to more completely support PM device, by doing proper hardare init/deinit in the PM action hook.
Diffstat (limited to 'app/module')
-rw-r--r--app/module/drivers/kscan/kscan_gpio_charlieplex.c69
-rw-r--r--app/module/drivers/kscan/kscan_gpio_direct.c33
-rw-r--r--app/module/drivers/kscan/kscan_gpio_matrix.c57
3 files changed, 146 insertions, 13 deletions
diff --git a/app/module/drivers/kscan/kscan_gpio_charlieplex.c b/app/module/drivers/kscan/kscan_gpio_charlieplex.c
index 3ecbcd6a0e..f48a6a2f40 100644
--- a/app/module/drivers/kscan/kscan_gpio_charlieplex.c
+++ b/app/module/drivers/kscan/kscan_gpio_charlieplex.c
@@ -12,6 +12,7 @@
#include <zephyr/drivers/kscan.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
+#include <zephyr/pm/device.h>
#include <zephyr/sys/__assert.h>
#include <zephyr/sys/util.h>
@@ -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 fa24e69e89..245e78b50c 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 8a3c39f2ba..e0c76395f6 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;