From f52a946553ae296cfafa9fe3459b6b4292a74277 Mon Sep 17 00:00:00 2001 From: Kim Streich Date: Tue, 3 May 2022 23:26:48 +0400 Subject: [PATCH 1/7] Re-init i2c and ssd on power domain on/off --- drivers/display/ssd1306.c | 31 ++++++++++++++++++++++++++++++- drivers/i2c/i2c_nrfx_twi.c | 8 ++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/display/ssd1306.c b/drivers/display/ssd1306.c index 9408ac4f95c1f6..bdfbb132c0a7bf 100644 --- a/drivers/display/ssd1306.c +++ b/drivers/display/ssd1306.c @@ -15,6 +15,7 @@ LOG_MODULE_REGISTER(ssd1306, CONFIG_DISPLAY_LOG_LEVEL); #include #include #include +#include #include "ssd1306_regs.h" #include @@ -425,6 +426,34 @@ static int ssd1306_init(const struct device *dev) return 0; } +#ifdef CONFIG_PM_DEVICE +static int ssd1306_pm_action(const struct device *dev, + enum pm_device_action action) +{ + int ret = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + LOG_DBG("Initializing display..."); + ssd1306_init(dev); + + break; + + case PM_DEVICE_ACTION_TURN_OFF: + // We don't need to do anything when turning off, but we also + // don't want to return -ENOTSUP + // So we keep this empty on purpose. + break; + + default: + ret = -ENOTSUP; + } + + return ret; +} +PM_DEVICE_DT_INST_DEFINE(0, ssd1306_pm_action); +#endif /* CONFIG_PM_DEVICE */ + static const struct ssd1306_config ssd1306_config = { #if DT_INST_ON_BUS(0, i2c) .bus = I2C_DT_SPEC_INST_GET(0), @@ -451,7 +480,7 @@ static struct display_driver_api ssd1306_driver_api = { .set_orientation = ssd1306_set_orientation, }; -DEVICE_DT_INST_DEFINE(0, ssd1306_init, NULL, +DEVICE_DT_INST_DEFINE(0, ssd1306_init, PM_DEVICE_DT_INST_GET(0), &ssd1306_driver, &ssd1306_config, POST_KERNEL, CONFIG_DISPLAY_INIT_PRIORITY, &ssd1306_driver_api); diff --git a/drivers/i2c/i2c_nrfx_twi.c b/drivers/i2c/i2c_nrfx_twi.c index 8dd760912af936..aeca8cb043ace4 100644 --- a/drivers/i2c/i2c_nrfx_twi.c +++ b/drivers/i2c/i2c_nrfx_twi.c @@ -228,10 +228,18 @@ static int twi_nrfx_pm_action(const struct device *dev, switch (action) { case PM_DEVICE_ACTION_RESUME: + LOG_DBG("Initializing i2c-twi..."); init_twi(dev); if (data->dev_config) { i2c_nrfx_twi_configure(dev, data->dev_config); } + + break; + + case PM_DEVICE_ACTION_TURN_OFF: + // We don't want to uninit as it causes issues on re-init + // But we also don't want to return -ENOTSUP + // So we keep this empty. break; case PM_DEVICE_ACTION_SUSPEND: From 0da7cd61b39fba14d7e726deec62b583407517b7 Mon Sep 17 00:00:00 2001 From: Flavio Ceolin Date: Wed, 5 Jan 2022 17:19:53 -0800 Subject: [PATCH 2/7] pm: device: Dynamically add a device to a power domain Add API to add devices to a power domain in runtime. The number of devices that can be added is defined in build time. The script gen_handles.py will check the number defined in `CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC` to resize the handles vector, adding empty slots in the supported sector to be used later. Signed-off-by: Flavio Ceolin --- CMakeLists.txt | 7 ++++ include/device.h | 13 ++++-- include/linker/common-ram.ld | 13 ++++++ include/linker/common-rom.ld | 2 + include/pm/device.h | 43 +++++++++++++++++++ kernel/Kconfig | 10 +++++ scripts/gen_handles.py | 4 ++ subsys/pm/Kconfig | 14 +++++++ subsys/pm/device.c | 80 ++++++++++++++++++++++++++++++++++++ 9 files changed, 183 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2684d0e869122f..5af9a858850a8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -801,6 +801,12 @@ zephyr_get_include_directories_for_lang(C STRIP_PREFIX # Don't use a -I prefix ) +if(CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC) + set(number_of_dynamic_devices ${CONFIG_PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM}) +else() + set(number_of_dynamic_devices 0) +endif() + if(CONFIG_HAS_DTS) # dev_handles.c is generated from ${ZEPHYR_LINK_STAGE_EXECUTABLE} by # gen_handles.py @@ -810,6 +816,7 @@ if(CONFIG_HAS_DTS) ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/gen_handles.py --output-source dev_handles.c + --num-dynamic-devices ${number_of_dynamic_devices} --kernel $ --zephyr-base ${ZEPHYR_BASE} --start-symbol "$" diff --git a/include/device.h b/include/device.h index f06cc06c78c3c0..02228a474cd32e 100644 --- a/include/device.h +++ b/include/device.h @@ -444,6 +444,12 @@ struct device_state { struct pm_device; +#ifdef CONFIG_HAS_DYNAMIC_DEVICE_HANDLES +#define Z_DEVICE_HANDLES_CONST +#else +#define Z_DEVICE_HANDLES_CONST const +#endif + /** * @brief Runtime device structure (in ROM) per driver instance */ @@ -465,7 +471,8 @@ struct device { * extracted with dedicated API, such as * device_required_handles_get(). */ - const device_handle_t *const handles; + Z_DEVICE_HANDLES_CONST device_handle_t * const handles; + #ifdef CONFIG_PM_DEVICE /** Reference to the device PM resources. */ struct pm_device * const pm; @@ -877,9 +884,9 @@ __deprecated static inline int device_usable_check(const struct device *dev) */ BUILD_ASSERT(sizeof(device_handle_t) == 2, "fix the linker scripts"); #define Z_DEVICE_DEFINE_HANDLES(node_id, dev_name, ...) \ - extern const device_handle_t \ + extern Z_DEVICE_HANDLES_CONST device_handle_t \ Z_DEVICE_HANDLE_NAME(node_id, dev_name)[]; \ - const device_handle_t \ + Z_DEVICE_HANDLES_CONST device_handle_t \ __aligned(sizeof(device_handle_t)) \ __attribute__((__weak__, \ __section__(".__device_handles_pass1"))) \ diff --git a/include/linker/common-ram.ld b/include/linker/common-ram.ld index 7df193531d4b7c..529734bd48abc7 100644 --- a/include/linker/common-ram.ld +++ b/include/linker/common-ram.ld @@ -45,6 +45,19 @@ } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) #endif +#if defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) + SECTION_DATA_PROLOGUE(device_handles,,) + { + __device_handles_start = .; +#ifdef LINKER_DEVICE_HANDLES_PASS1 + KEEP(*(SORT(.__device_handles_pass1*))); +#else + KEEP(*(SORT(.__device_handles_pass2*))); +#endif /* LINKER_DEVICE_HANDLES_PASS1 */ + __device_handles_end = .; + } GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) +#endif /* CONFIG_HAS_DYNAMIC_DEVICE_HANDLES */ + SECTION_DATA_PROLOGUE(initshell,,) { /* link in shell initialization objects for all modules that diff --git a/include/linker/common-rom.ld b/include/linker/common-rom.ld index afdc76434bbf39..d1e48172100507 100644 --- a/include/linker/common-rom.ld +++ b/include/linker/common-rom.ld @@ -216,6 +216,7 @@ KEEP(*(".dbg_thread_info")); } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) +#if !defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) SECTION_DATA_PROLOGUE(device_handles,,) { __device_handles_start = .; @@ -226,3 +227,4 @@ #endif /* LINKER_DEVICE_HANDLES_PASS1 */ __device_handles_end = .; } GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) +#endif /* !CONFIG_HAS_DYNAMIC_DEVICE_HANDLES */ diff --git a/include/pm/device.h b/include/pm/device.h index 028dbd06feddf3..231e55c84a6421 100644 --- a/include/pm/device.h +++ b/include/pm/device.h @@ -507,6 +507,36 @@ bool pm_device_state_is_locked(const struct device *dev); */ bool pm_device_on_power_domain(const struct device *dev); +/** + * @brief Add a device to a power domain. + * + * This function adds a device to a given power domain. + * + * @param dev Device to be added to the power domain. + * @param domain Power domain. + * + * @retval 0 If successful. + * @retval -EALREADY If device is already part of the power domain. + * @retval -ENOSYS If the application was built without power domain support. + * @retval -ENOSPC If there is no space available in the power domain to add the device. + */ +int pm_device_power_domain_add(const struct device *dev, + const struct device *domain); + +/** + * @brief Remove a device from a power domain. + * + * This function removes a device from a given power domain. + * + * @param dev Device to be removed from the power domain. + * @param domain Power domain. + * + * @retval 0 If successful. + * @retval -ENOSYS If the application was built without power domain support. + * @retval -ENOENT If device is not in the given domain. + */ +int pm_device_power_domain_remove(const struct device *dev, + const struct device *domain); #else static inline void pm_device_busy_set(const struct device *dev) { @@ -556,6 +586,19 @@ static inline bool pm_device_on_power_domain(const struct device *dev) ARG_UNUSED(dev); return false; } + +static inline int pm_device_power_domain_add(const struct device *dev, + const struct device *domain) +{ + return -ENOSYS; +} + +static inline int pm_device_power_domain_remove(const struct device *dev, + const struct device *domain) +{ + return -ENOSYS; +} + #endif /* CONFIG_PM_DEVICE */ /** diff --git a/kernel/Kconfig b/kernel/Kconfig index 6e040d045c1dfb..1749c0b4694cd7 100644 --- a/kernel/Kconfig +++ b/kernel/Kconfig @@ -920,4 +920,14 @@ config THREAD_LOCAL_STORAGE endmenu +menu "Device Options" + +config HAS_DYNAMIC_DEVICE_HANDLES + bool + help + Hidden option that makes possible to manipulate device handles at + runtime. + +endmenu + rsource "Kconfig.vm" diff --git a/scripts/gen_handles.py b/scripts/gen_handles.py index aa046a13b4db7c..ba027e1ff16bac 100755 --- a/scripts/gen_handles.py +++ b/scripts/gen_handles.py @@ -62,6 +62,8 @@ def parse_args(): parser.add_argument("-k", "--kernel", required=True, help="Input zephyr ELF binary") + parser.add_argument("-d", "--num-dynamic-devices", required=False, default=0, + type=int, help="Input number of dynamic devices allowed") parser.add_argument("-o", "--output-source", required=True, help="Output source file") @@ -112,6 +114,7 @@ def symbol_handle_data(elf, sym): # These match the corresponding constants in DEVICE_HANDLE_SEP = -32768 DEVICE_HANDLE_ENDS = 32767 +DEVICE_HANDLE_NULL = 0 def handle_name(hdl): if hdl == DEVICE_HANDLE_SEP: return "DEVICE_HANDLE_SEP" @@ -336,6 +339,7 @@ def main(): else: sup_paths.append('(%s)' % dn.path) hdls.extend(dn.__device.dev_handle for dn in sn.__supports) + hdls.extend(DEVICE_HANDLE_NULL for dn in range(args.num_dynamic_devices)) # Terminate the array with the end symbol hdls.append(DEVICE_HANDLE_ENDS) diff --git a/subsys/pm/Kconfig b/subsys/pm/Kconfig index 0938d823c62458..7bd73170c71606 100644 --- a/subsys/pm/Kconfig +++ b/subsys/pm/Kconfig @@ -63,6 +63,20 @@ config PM_DEVICE_POWER_DOMAIN devices that depend on a domain will be notified when this domain is suspended or resumed. +config PM_DEVICE_POWER_DOMAIN_DYNAMIC + bool "Dynamically bind devices to a Power Pomain" + depends on PM_DEVICE_POWER_DOMAIN + select HAS_DYNAMIC_DEVICE_HANDLES + help + Enable support for dynamically bind devices to a Power Domain. + +config PM_DEVICE_POWER_DOMAIN_DYNAMIC_NUM + int "Number of devices that can dynamically be bind to a Power Domain" + depends on PM_DEVICE_POWER_DOMAIN_DYNAMIC + default 1 + help + The number of devices that can dynamically be bind to a Power Domain. + config PM_DEVICE_RUNTIME bool "Runtime Device Power Management" help diff --git a/subsys/pm/device.c b/subsys/pm/device.c index 92c2598c5056ae..bf31a8da4e10ad 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -154,6 +154,82 @@ int pm_device_action_run(const struct device *dev, return 0; } +static int power_domain_add_or_remove(const struct device *dev, + const struct device *domain, + bool add) +{ +#if defined(CONFIG_HAS_DYNAMIC_DEVICE_HANDLES) + device_handle_t *rv = domain->handles; + device_handle_t dev_handle = -1; + extern const struct device __device_start[]; + extern const struct device __device_end[]; + size_t i, region = 0; + size_t numdev = __device_end - __device_start; + + /* + * Supported devices are stored as device handle and not + * device pointers. So, it is necessary to find what is + * the handle associated to the given device. + */ + for (i = 0; i < numdev; i++) { + if (&__device_start[i] == dev) { + dev_handle = i + 1; + break; + } + } + + /* + * The last part is to find an available slot in the + * supported section of handles array and replace it + * with the device handle. + */ + while (region != 2) { + if (*rv == DEVICE_HANDLE_SEP) { + region++; + } + rv++; + } + + i = 0; + while (rv[i] != DEVICE_HANDLE_ENDS) { + if (add == false) { + if (rv[i] == dev_handle) { + dev->pm->domain = NULL; + rv[i] = DEVICE_HANDLE_NULL; + return 0; + } + } else { + if (rv[i] == DEVICE_HANDLE_NULL) { + dev->pm->domain = domain; + rv[i] = dev_handle; + return 0; + } + } + ++i; + } + + return add ? -ENOSPC : -ENOENT; +#else + ARG_UNUSED(dev); + ARG_UNUSED(domain); + ARG_UNUSED(add); + + return -ENOSYS; +#endif +} + +int pm_device_power_domain_remove(const struct device *dev, + const struct device *domain) +{ + return power_domain_add_or_remove(dev, domain, false); +} + +int pm_device_power_domain_add(const struct device *dev, + const struct device *domain) +{ + return power_domain_add_or_remove(dev, domain, true); +} + void pm_device_children_action_run(const struct device *dev, enum pm_device_action action, pm_device_action_failed_cb_t failure_cb) @@ -174,6 +250,10 @@ void pm_device_children_action_run(const struct device *dev, device_handle_t dh = handles[i]; const struct device *cdev = device_from_handle(dh); + if (cdev == NULL) { + continue; + } + rc = pm_device_action_run(cdev, action); if ((failure_cb != NULL) && (rc < 0)) { /* Stop the iteration if the callback requests it */ From da7f2cebca1a4c0bd9d950b48773e84f23bd60df Mon Sep 17 00:00:00 2001 From: Kim Streich Date: Wed, 4 May 2022 20:51:43 +0400 Subject: [PATCH 3/7] Power Domain GPIO: Add support for startup_delay_us and off_on_delay_us --- drivers/power_domain/power_domain_gpio.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 6fbf012e7beabc..983aa812fdb5d2 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -43,13 +43,24 @@ static int pd_gpio_pm_action(const struct device *dev, case PM_DEVICE_ACTION_RESUME: /* Switch power on */ gpio_pin_set_dt(&cfg->enable, 1); + + if(cfg->startup_delay_us > 0) { + k_sleep(K_USEC(cfg->startup_delay_us)); + } + LOG_DBG("%s is now ON", dev->name); + /* Notify supported devices they are now powered */ pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_ON, NULL); break; case PM_DEVICE_ACTION_SUSPEND: /* Notify supported devices power is going down */ pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_OFF, NULL); + + if(cfg->off_on_delay_us > 0) { + k_sleep(K_USEC(cfg->off_on_delay_us)); + } + /* Switch power off */ gpio_pin_set_dt(&cfg->enable, 0); LOG_DBG("%s is now OFF and powered", dev->name); @@ -57,10 +68,19 @@ static int pd_gpio_pm_action(const struct device *dev, case PM_DEVICE_ACTION_TURN_ON: /* Actively control the enable pin now that the device is powered */ gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); + + if(cfg->startup_delay_us > 0) { + k_sleep(K_USEC(cfg->startup_delay_us)); + } + LOG_DBG("%s is OFF and powered", dev->name); break; case PM_DEVICE_ACTION_TURN_OFF: /* Let the enable pin float while device is not powered */ + if(cfg->startup_delay_us > 0) { + k_sleep(K_USEC(cfg->startup_delay_us)); + } + gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); LOG_DBG("%s is OFF and not powered", dev->name); break; From 526e7fb0169e26d99aa5e42cd4ae836604ae03f6 Mon Sep 17 00:00:00 2001 From: Kim Streich Date: Wed, 4 May 2022 21:00:56 +0400 Subject: [PATCH 4/7] Power Domain GPIO: Ensure children receive the same pm_action notification as the parent --- drivers/power_domain/power_domain_gpio.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 983aa812fdb5d2..b1469c15c6ca3c 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -51,11 +51,11 @@ static int pd_gpio_pm_action(const struct device *dev, LOG_DBG("%s is now ON", dev->name); /* Notify supported devices they are now powered */ - pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_ON, NULL); + pm_device_children_action_run(dev, action, NULL); break; case PM_DEVICE_ACTION_SUSPEND: /* Notify supported devices power is going down */ - pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_OFF, NULL); + pm_device_children_action_run(dev, action, NULL); if(cfg->off_on_delay_us > 0) { k_sleep(K_USEC(cfg->off_on_delay_us)); @@ -74,15 +74,23 @@ static int pd_gpio_pm_action(const struct device *dev, } LOG_DBG("%s is OFF and powered", dev->name); + + /* Notify supported devices they are now powered */ + pm_device_children_action_run(dev, action, NULL); + break; case PM_DEVICE_ACTION_TURN_OFF: - /* Let the enable pin float while device is not powered */ - if(cfg->startup_delay_us > 0) { - k_sleep(K_USEC(cfg->startup_delay_us)); + /* Notify supported devices power is going down */ + pm_device_children_action_run(dev, action, NULL); + + if(cfg->off_on_delay_us > 0) { + k_sleep(K_USEC(cfg->off_on_delay_us)); } + /* Let the enable pin float while device is not powered */ gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); LOG_DBG("%s is OFF and not powered", dev->name); + break; default: rc = -ENOTSUP; From aa17db3397cd5b41495dd560d8ebd5cbde5be573 Mon Sep 17 00:00:00 2001 From: Kim Streich Date: Thu, 5 May 2022 23:14:21 +0400 Subject: [PATCH 5/7] Added proper turning on and off of pins Removed configure lines --- drivers/power_domain/power_domain_gpio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index b1469c15c6ca3c..21f253ea41c04e 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -67,7 +67,7 @@ static int pd_gpio_pm_action(const struct device *dev, break; case PM_DEVICE_ACTION_TURN_ON: /* Actively control the enable pin now that the device is powered */ - gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); + gpio_pin_set_dt(&cfg->enable, 1); if(cfg->startup_delay_us > 0) { k_sleep(K_USEC(cfg->startup_delay_us)); @@ -88,7 +88,8 @@ static int pd_gpio_pm_action(const struct device *dev, } /* Let the enable pin float while device is not powered */ - gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); + gpio_pin_set_dt(&cfg->enable, 0); + LOG_DBG("%s is OFF and not powered", dev->name); break; From b659ac051c7de68d55287a6984ed09bcdce58da9 Mon Sep 17 00:00:00 2001 From: Kim Streich Date: Thu, 5 May 2022 22:36:37 +0400 Subject: [PATCH 6/7] pm: Added pm_device_action_str Added log to pd_gpio_pm_action --- drivers/power_domain/power_domain_gpio.c | 2 ++ include/pm/device.h | 7 +++++++ subsys/pm/device.c | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 21f253ea41c04e..9caaa66617aed8 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -36,6 +36,8 @@ const char *actions[] = { static int pd_gpio_pm_action(const struct device *dev, enum pm_device_action action) { + LOG_DBG("In pd_gpio_pm_action for power domain %s with action: %s", dev->name, pm_device_action_str(action)); + const struct pd_gpio_config *cfg = dev->config; int rc = 0; diff --git a/include/pm/device.h b/include/pm/device.h index 231e55c84a6421..57c5b8232f1174 100644 --- a/include/pm/device.h +++ b/include/pm/device.h @@ -314,6 +314,13 @@ struct pm_device { */ const char *pm_device_state_str(enum pm_device_state state); +/** + * @brief Get name of device PM action + * + * @param action Action id which name should be returned + */ +const char *pm_device_action_str(enum pm_device_action action); + /** * @brief Set the power state of a device. * diff --git a/subsys/pm/device.c b/subsys/pm/device.c index bf31a8da4e10ad..cf06d520ac8479 100644 --- a/subsys/pm/device.c +++ b/subsys/pm/device.c @@ -25,6 +25,24 @@ const char *pm_device_state_str(enum pm_device_state state) } } +const char *pm_device_action_str(enum pm_device_action action) +{ + switch (action) { + case PM_DEVICE_ACTION_SUSPEND: + return "suspend"; + case PM_DEVICE_ACTION_RESUME: + return "resume"; + case PM_DEVICE_ACTION_TURN_OFF: + return "turn_off"; + case PM_DEVICE_ACTION_TURN_ON: + return "turn_on"; + case PM_DEVICE_ACTION_FORCE_SUSPEND: + return "force_suspend"; + default: + return "unknown_action"; + } +} + int pm_device_state_set(const struct device *dev, enum pm_device_state state) { From f5c43dc9578bf4eb69920ab30cd07d3686eacba2 Mon Sep 17 00:00:00 2001 From: Kim Streich Date: Sat, 7 May 2022 11:47:35 +0400 Subject: [PATCH 7/7] =?UTF-8?q?Power=20Domain=20GPIO:=20Ensure=20init=20do?= =?UTF-8?q?esn=E2=80=99t=20fail=20if=20pin=20configuration=20fails?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a power domain is connected to another power domain,`pd_gpio_init` attempts to configure the gpio pin to `GPIO_DISCONNECTED`. But if that failed, the init function returned -EIO, which caused the device to be marked as not initialized / ready. This meant that it couldn’t be retrieved through `device_get_binding()`. --- drivers/power_domain/power_domain_gpio.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c index 9caaa66617aed8..ff93928a586625 100644 --- a/drivers/power_domain/power_domain_gpio.c +++ b/drivers/power_domain/power_domain_gpio.c @@ -13,7 +13,7 @@ #include #include -LOG_MODULE_REGISTER(power_domain_gpio, LOG_LEVEL_INF); +LOG_MODULE_REGISTER(power_domain_gpio, CONFIG_PM_DEVICE_LOG_LEVEL); struct pd_gpio_config { struct gpio_dt_spec enable; @@ -104,6 +104,8 @@ static int pd_gpio_pm_action(const struct device *dev, static int pd_gpio_init(const struct device *dev) { + LOG_DBG("Initing power-domain-gpio: %s", dev->name); + const struct pd_gpio_config *cfg = dev->config; int rc; @@ -116,12 +118,18 @@ static int pd_gpio_init(const struct device *dev) /* Device is unpowered */ pm_device_runtime_init_off(dev); rc = gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); + if(rc != 0) { + LOG_WRN("Could not configure pin to GPIO_DISCONNECTED: %d", rc); + } } else { pm_device_runtime_init_suspended(dev); rc = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); + if(rc != 0) { + LOG_WRN("Could not configure pin to GPIO_OUTPUT_INACTIVE: %d", rc); + } } - return rc; + return 0; } #define POWER_DOMAIN_DEVICE(id) \