diff --git a/app/src/ext_power_generic.c b/app/src/ext_power_generic.c index 48170304..76ee00c7 100644 --- a/app/src/ext_power_generic.c +++ b/app/src/ext_power_generic.c @@ -6,8 +6,11 @@ #define DT_DRV_COMPAT zmk_ext_power_generic +#include #include #include +#include +#include #include #include @@ -25,8 +28,33 @@ struct ext_power_generic_config { struct ext_power_generic_data { struct device *gpio; bool status; +#if IS_ENABLED(CONFIG_SETTINGS) + bool settings_init; +#endif }; +#if IS_ENABLED(CONFIG_SETTINGS) +static void ext_power_save_state_work(struct k_work *work) { + char setting_path[40]; + struct device *ext_power = device_get_binding(DT_INST_LABEL(0)); + struct ext_power_generic_data *data = ext_power->driver_data; + + snprintf(setting_path, 40, "ext_power/state/%s", DT_INST_LABEL(0)); + settings_save_one(setting_path, &data->status, sizeof(data->status)); +} + +static struct k_delayed_work ext_power_save_work; +#endif + +int ext_power_save_state() { +#if IS_ENABLED(CONFIG_SETTINGS) + k_delayed_work_cancel(&ext_power_save_work); + return k_delayed_work_submit(&ext_power_save_work, K_MINUTES(1)); +#else + return 0; +#endif +} + static int ext_power_generic_enable(struct device *dev) { struct ext_power_generic_data *data = dev->driver_data; const struct ext_power_generic_config *config = dev->config_info; @@ -36,7 +64,7 @@ static int ext_power_generic_enable(struct device *dev) { return -EIO; } data->status = true; - return 0; + return ext_power_save_state(); } static int ext_power_generic_disable(struct device *dev) { @@ -48,7 +76,7 @@ static int ext_power_generic_disable(struct device *dev) { return -EIO; } data->status = false; - return 0; + return ext_power_save_state(); } static int ext_power_generic_get(struct device *dev) { @@ -56,6 +84,46 @@ static int ext_power_generic_get(struct device *dev) { return data->status; } +#if IS_ENABLED(CONFIG_SETTINGS) +static int ext_power_settings_set(const char *name, size_t len, settings_read_cb read_cb, + void *cb_arg) { + const char *next; + int rc; + + if (settings_name_steq(name, DT_INST_LABEL(0), &next) && !next) { + struct device *ext_power = device_get_binding(DT_INST_LABEL(0)); + struct ext_power_generic_data *data = ext_power->driver_data; + + if (len != sizeof(data->status)) { + return -EINVAL; + } + + rc = read_cb(cb_arg, &data->status, sizeof(data->status)); + if (rc >= 0) { + data->settings_init = true; + + if (ext_power == NULL) { + LOG_ERR("Unable to retrieve ext_power device: %s", DT_INST_LABEL(0)); + return -EIO; + } + + if (data->status) { + ext_power_generic_enable(ext_power); + } else { + ext_power_generic_disable(ext_power); + } + + return 0; + } + return rc; + } + return -ENOENT; +} + +struct settings_handler ext_power_conf = {.name = "ext_power/state", + .h_set = ext_power_settings_set}; +#endif + static int ext_power_generic_init(struct device *dev) { struct ext_power_generic_data *data = dev->driver_data; const struct ext_power_generic_config *config = dev->config_info; @@ -71,6 +139,24 @@ static int ext_power_generic_init(struct device *dev) { return -EIO; } +#if IS_ENABLED(CONFIG_SETTINGS) + settings_register(&ext_power_conf); + k_delayed_work_init(&ext_power_save_work, ext_power_save_state_work); + + // Set default value (on) if settings isn't set + settings_load_subtree("ext_power"); + if (!data->settings_init) { + + data->status = true; + k_delayed_work_submit(&ext_power_save_work, K_NO_WAIT); + + ext_power_enable(dev); + } +#else + // Default to the ext_power being open when no settings + ext_power_enable(dev); +#endif + return 0; } @@ -79,13 +165,18 @@ static const struct ext_power_generic_config config = { .pin = DT_INST_GPIO_PIN(0, control_gpios), .flags = DT_INST_GPIO_FLAGS(0, control_gpios)}; -static struct ext_power_generic_data data = {.status = false}; +static struct ext_power_generic_data data = { + .status = false, +#if IS_ENABLED(CONFIG_SETTINGS) + .settings_init = false, +#endif +}; static const struct ext_power_api api = {.enable = ext_power_generic_enable, .disable = ext_power_generic_disable, .get = ext_power_generic_get}; DEVICE_AND_API_INIT(ext_power_generic, DT_INST_LABEL(0), ext_power_generic_init, &data, &config, - APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &api); + APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY, &api); #endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */ diff --git a/app/src/main.c b/app/src/main.c index 0551356d..eb0275bd 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -20,20 +20,12 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL); #define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID) void main(void) { - struct device *ext_power; LOG_INF("Welcome to ZMK!\n"); if (zmk_kscan_init(ZMK_KSCAN_DEV) != 0) { return; } - // Enable the external VCC output - ext_power = device_get_binding("EXT_POWER"); - if (ext_power != NULL) { - const struct ext_power_api *ext_power_api = ext_power->driver_api; - ext_power_api->enable(ext_power); - } - #ifdef CONFIG_ZMK_DISPLAY zmk_display_init();