Skip to content

Commit

Permalink
Merge pull request zephyrproject-rtos#29 from whisperai/nlapp/gen2/pu…
Browse files Browse the repository at this point in the history
…ll-in-power-domain-gpio-fixes

Nlapp/gen2/pull in power domain gpio fixes
  • Loading branch information
NickolasLapp authored Sep 26, 2022
2 parents 0c8cfdb + 291f7db commit acbb960
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 17 deletions.
5 changes: 5 additions & 0 deletions drivers/power_domain/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,13 @@ menuconfig POWER_DOMAIN

if POWER_DOMAIN

module = POWER_DOMAIN
module-str = power_domain
source "subsys/logging/Kconfig.template.log_config"

config POWER_DOMAIN_GPIO
bool "GPIO controlled power domain"
depends on GPIO
depends on TIMEOUT_64BIT

endif
44 changes: 27 additions & 17 deletions drivers/power_domain/power_domain_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@

#define DT_DRV_COMPAT power_domain_gpio

#include <kernel.h>
#include <drivers/gpio.h>
#include <pm/device.h>
#include <pm/device_runtime.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/device_runtime.h>

#include <logging/log.h>
LOG_MODULE_REGISTER(power_domain_gpio, LOG_LEVEL_INF);
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(power_domain_gpio, CONFIG_POWER_DOMAIN_LOG_LEVEL);

struct pd_gpio_config {
struct gpio_dt_spec enable;
Expand All @@ -22,28 +22,32 @@ struct pd_gpio_config {
};

struct pd_gpio_data {
k_timeout_t last_boot;
k_timeout_t next_boot;
};

const char *actions[] = {
[PM_DEVICE_ACTION_RESUME] = "RESUME",
[PM_DEVICE_ACTION_SUSPEND] = "SUSPEND",
[PM_DEVICE_ACTION_TURN_ON] = "TURN ON",
[PM_DEVICE_ACTION_TURN_OFF] = "TURN OFF"
};


static int pd_gpio_pm_action(const struct device *dev,
enum pm_device_action action)
{
const struct pd_gpio_config *cfg = dev->config;
struct pd_gpio_data *data = dev->data;
int64_t next_boot_ticks;
int rc = 0;

/* Validate that blocking API's can be used */
if (!k_can_yield()) {
LOG_ERR("Blocking actions cannot run in this context");
return -ENOTSUP;
}

switch (action) {
case PM_DEVICE_ACTION_RESUME:
/* Wait until we can boot again */
k_sleep(data->next_boot);
/* Switch power on */
gpio_pin_set_dt(&cfg->enable, 1);
LOG_DBG("%s is now ON", dev->name);
LOG_INF("%s is now ON", dev->name);
/* Wait for domain to come up */
k_sleep(K_USEC(cfg->startup_delay_us));
/* Notify supported devices they are now powered */
pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_ON, NULL);
break;
Expand All @@ -52,7 +56,10 @@ static int pd_gpio_pm_action(const struct device *dev,
pm_device_children_action_run(dev, PM_DEVICE_ACTION_TURN_OFF, NULL);
/* Switch power off */
gpio_pin_set_dt(&cfg->enable, 0);
LOG_DBG("%s is now OFF and powered", dev->name);
LOG_INF("%s is now OFF", dev->name);
/* Store next time we can boot */
next_boot_ticks = k_uptime_ticks() + k_us_to_ticks_ceil32(cfg->off_on_delay_us);
data->next_boot = K_TIMEOUT_ABS_TICKS(next_boot_ticks);
break;
case PM_DEVICE_ACTION_TURN_ON:
/* Actively control the enable pin now that the device is powered */
Expand All @@ -74,12 +81,15 @@ static int pd_gpio_pm_action(const struct device *dev,
static int pd_gpio_init(const struct device *dev)
{
const struct pd_gpio_config *cfg = dev->config;
struct pd_gpio_data *data = dev->data;
int rc;

if (!device_is_ready(cfg->enable.port)) {
LOG_ERR("GPIO port %s is not ready", cfg->enable.port->name);
return -ENODEV;
}
/* We can't know how long the domain has been off for before boot */
data->next_boot = K_TIMEOUT_ABS_US(cfg->off_on_delay_us);

if (pm_device_on_power_domain(dev)) {
/* Device is unpowered */
Expand Down
13 changes: 13 additions & 0 deletions include/zephyr/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,19 @@ __syscall int32_t k_usleep(int32_t us);
*/
__syscall void k_busy_wait(uint32_t usec_to_wait);

/**
* @brief Check whether it is possible to yield in the current context.
*
* This routine checks whether the kernel is in a state where it is possible to
* yield or call blocking API's. It should be used by code that needs to yield
* to perform correctly, but can feasibly be called from contexts where that
* is not possible. For example in the PRE_KERNEL initialization step, or when
* being run from the idle thread.
*
* @return True if it is possible to yield in the current context, false otherwise.
*/
bool k_can_yield(void);

/**
* @brief Yield the current thread.
*
Expand Down
6 changes: 6 additions & 0 deletions kernel/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -1325,6 +1325,12 @@ static inline void z_vrfy_k_thread_deadline_set(k_tid_t tid, int deadline)
#endif
#endif

bool k_can_yield(void)
{
return !(k_is_pre_kernel() || k_is_in_isr() ||
z_is_idle_thread_object(_current));
}

void z_impl_k_yield(void)
{
__ASSERT(!arch_is_in_isr(), "");
Expand Down

0 comments on commit acbb960

Please sign in to comment.