From ccdc009077e7aed2b8e9361fedb725fec9ab195e Mon Sep 17 00:00:00 2001 From: Jordan Yates Date: Thu, 6 Jan 2022 22:17:39 +1000 Subject: [PATCH] drivers: power_domain: gpio controlled domain Initial implementation of a simple GPIO controlled power domain. It exposes no API of its own, all functionality is contained inside the runtime power management callbacks. Signed-off-by: Jordan Yates --- drivers/CMakeLists.txt | 1 + drivers/Kconfig | 2 + drivers/power_domain/CMakeLists.txt | 6 + drivers/power_domain/Kconfig | 15 +++ drivers/power_domain/power_domain_gpio.c | 109 ++++++++++++++++++ .../power-domain/power-domain-gpio.yaml | 32 +++++ 6 files changed, 165 insertions(+) create mode 100644 drivers/power_domain/CMakeLists.txt create mode 100644 drivers/power_domain/Kconfig create mode 100644 drivers/power_domain/power_domain_gpio.c create mode 100644 dts/bindings/power-domain/power-domain-gpio.yaml diff --git a/drivers/CMakeLists.txt b/drivers/CMakeLists.txt index 1387f599695..83f4d9572d6 100644 --- a/drivers/CMakeLists.txt +++ b/drivers/CMakeLists.txt @@ -46,6 +46,7 @@ add_subdirectory_ifdef(CONFIG_REGULATOR regulator) add_subdirectory_ifdef(CONFIG_MEMC memc) add_subdirectory_ifdef(CONFIG_VIRTUALIZATION virtualization) add_subdirectory_ifdef(CONFIG_PM_CPU_OPS pm_cpu_ops) +add_subdirectory_ifdef(CONFIG_POWER_DOMAIN power_domain) add_subdirectory_ifdef(CONFIG_FLASH_HAS_DRIVER_ENABLED flash) add_subdirectory_ifdef(CONFIG_SERIAL_HAS_DRIVER serial) diff --git a/drivers/Kconfig b/drivers/Kconfig index 29696003497..52989ad0124 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -129,4 +129,6 @@ source "drivers/mbox/Kconfig" source "drivers/mm/Kconfig" +source "drivers/power_domain/Kconfig" + endmenu diff --git a/drivers/power_domain/CMakeLists.txt b/drivers/power_domain/CMakeLists.txt new file mode 100644 index 00000000000..a2aed23c6af --- /dev/null +++ b/drivers/power_domain/CMakeLists.txt @@ -0,0 +1,6 @@ +# Copyright (c) 2022, CSIRO +# SPDX-License-Identifier: Apache-2.0 + +zephyr_library() + +zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_GPIO power_domain_gpio.c) diff --git a/drivers/power_domain/Kconfig b/drivers/power_domain/Kconfig new file mode 100644 index 00000000000..da8118d854b --- /dev/null +++ b/drivers/power_domain/Kconfig @@ -0,0 +1,15 @@ +# Copyright (c) 2022, CSIRO. +# SPDX-License-Identifier: Apache-2.0 + +menuconfig POWER_DOMAIN + bool "Power domain drivers" + help + Include drivers for power domains in system config + +if POWER_DOMAIN + +config POWER_DOMAIN_GPIO + bool "GPIO controlled power domain" + depends on GPIO + +endif diff --git a/drivers/power_domain/power_domain_gpio.c b/drivers/power_domain/power_domain_gpio.c new file mode 100644 index 00000000000..6fbf012e7be --- /dev/null +++ b/drivers/power_domain/power_domain_gpio.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2022, Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT power_domain_gpio + +#include +#include +#include +#include + +#include +LOG_MODULE_REGISTER(power_domain_gpio, LOG_LEVEL_INF); + +struct pd_gpio_config { + struct gpio_dt_spec enable; + uint32_t startup_delay_us; + uint32_t off_on_delay_us; +}; + +struct pd_gpio_data { + k_timeout_t last_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; + int rc = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + /* Switch power on */ + gpio_pin_set_dt(&cfg->enable, 1); + 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); + /* Switch power off */ + gpio_pin_set_dt(&cfg->enable, 0); + LOG_DBG("%s is now OFF and powered", dev->name); + 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); + 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 */ + gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); + LOG_DBG("%s is OFF and not powered", dev->name); + break; + default: + rc = -ENOTSUP; + } + + return rc; +} + +static int pd_gpio_init(const struct device *dev) +{ + const struct pd_gpio_config *cfg = dev->config; + int rc; + + if (!device_is_ready(cfg->enable.port)) { + LOG_ERR("GPIO port %s is not ready", cfg->enable.port->name); + return -ENODEV; + } + + if (pm_device_on_power_domain(dev)) { + /* Device is unpowered */ + pm_device_runtime_init_off(dev); + rc = gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED); + } else { + pm_device_runtime_init_suspended(dev); + rc = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE); + } + + return rc; +} + +#define POWER_DOMAIN_DEVICE(id) \ + static const struct pd_gpio_config pd_gpio_##id##_cfg = { \ + .enable = GPIO_DT_SPEC_INST_GET(id, enable_gpios), \ + .startup_delay_us = DT_INST_PROP(id, startup_delay_us), \ + .off_on_delay_us = DT_INST_PROP(id, off_on_delay_us), \ + }; \ + static struct pd_gpio_data pd_gpio_##id##_data; \ + PM_DEVICE_DT_INST_DEFINE(id, pd_gpio_pm_action); \ + DEVICE_DT_INST_DEFINE(id, pd_gpio_init, PM_DEVICE_DT_INST_GET(id), \ + &pd_gpio_##id##_data, &pd_gpio_##id##_cfg, \ + POST_KERNEL, 75, \ + NULL); + +DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE) diff --git a/dts/bindings/power-domain/power-domain-gpio.yaml b/dts/bindings/power-domain/power-domain-gpio.yaml new file mode 100644 index 00000000000..e9bff7d77ec --- /dev/null +++ b/dts/bindings/power-domain/power-domain-gpio.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2022, CSIRO +# SPDX-License-Identifier: Apache-2.0 + +description: Simple GPIO controlled power domain + +compatible: "power-domain-gpio" + +include: power-domain.yaml + +properties: + enable-gpios: + type: phandle-array + required: true + description: | + GPIO to use to enable/disable the regulator. + + Unlike the gpio property in the Linux bindings this array must + provide the GPIO polarity and open-drain status in the phandle + selector. The Linux enable-active-high and gpio-open-drain + properties are not valid for Zephyr devicetree files. + + startup-delay-us: + type: int + required: false + default: 0 + description: Startup time, in microseconds + + off-on-delay-us: + type: int + required: false + default: 0 + description: Off delay time, in microseconds