power_domain: gpio: use on-off and startup time
Respect the configured values for how long the domain takes to turn on, and how long the domain needs to be off for before it can be repowered. As these actions can block, guard the transition function with pm_device_action_can_block. To avoid system PM being able to turn the domain off but not back on again, guard the entire implementation. Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
This commit is contained in:
parent
31ad7e2bd4
commit
d1ab0f6b6e
2 changed files with 20 additions and 1 deletions
|
@ -11,5 +11,6 @@ if POWER_DOMAIN
|
|||
config POWER_DOMAIN_GPIO
|
||||
bool "GPIO controlled power domain"
|
||||
depends on GPIO
|
||||
depends on TIMEOUT_64BIT
|
||||
|
||||
endif
|
||||
|
|
|
@ -22,20 +22,32 @@ struct pd_gpio_config {
|
|||
};
|
||||
|
||||
struct pd_gpio_data {
|
||||
k_timeout_t last_boot;
|
||||
k_timeout_t next_boot;
|
||||
};
|
||||
|
||||
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);
|
||||
/* 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;
|
||||
|
@ -45,6 +57,9 @@ static int pd_gpio_pm_action(const struct device *dev,
|
|||
/* Switch power off */
|
||||
gpio_pin_set_dt(&cfg->enable, 0);
|
||||
LOG_DBG("%s is now OFF and powered", 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 */
|
||||
|
@ -66,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 */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue