Skip to content

Commit 0102e49

Browse files
authored
drivers: Added initial support for power domains (#169)
Added needed functionality for power domains. Signed-off-by: Jared Baumann <jared.baumann8@t-mobile.com>
1 parent b794682 commit 0102e49

File tree

11 files changed

+320
-154
lines changed

11 files changed

+320
-154
lines changed

.gitattributes

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ drivers/modem/modem_socket.c merge=ours
117117
drivers/modem/modem_socket.h merge=ours
118118
drivers/modem/murata-1sc.c merge=ours
119119
drivers/pinctrl/pinctrl_gecko.c merge=ours
120+
drivers/power_domain/CMakeLists.txt merge=ours
121+
drivers/power_domain/Kconfig merge=ours
122+
drivers/power_domain/power_domain_gpio.c merge=ours
123+
drivers/power_domain/power_domain_regulator.c merge=ours
120124
drivers/regulator/CMakeLists.txt merge=ours
121125
drivers/regulator/Kconfig merge=ours
122126
drivers/regulator/Kconfig.act81461 merge=ours
@@ -161,6 +165,8 @@ dts/arm/silabs/efm32pg12b.dtsi merge=ours
161165
dts/arm/silabs/efr32mg.dtsi merge=ours
162166
dts/bindings/fuel-gauge/qorvo,act81461_alpc.yaml merge=ours
163167
dts/bindings/modem/murata,1sc.yaml merge=ours
168+
dts/bindings/power-domain/power-domain-gpio.yaml merge=ours
169+
dts/bindings/power-domain/power-domain-regulator.yaml merge=ours
164170
dts/bindings/regulator/qorvo,act81461.yaml merge=ours
165171
dts/bindings/rtc/silabs,gecko-stimer.yaml merge=ours
166172
dts/bindings/sensor/ams,as6212.yaml merge=ours

boards/arm/tmo_dev_edge/tmo_dev_edge.dts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@
102102
regulator-name = "bq24250rge";
103103
regulator-boot-on;
104104
};
105+
106+
gnss_ldo_domain: gnss_pwr {
107+
compatible = "power-domain-gpio";
108+
enable-gpios = <&gpiof 10 GPIO_ACTIVE_HIGH>;
109+
boot-on;
110+
};
105111
};
106112

107113
&cpu0 {
@@ -255,6 +261,7 @@
255261
pwr-gpios = <&gpiof 10 GPIO_ACTIVE_HIGH>;
256262
rst-gpios = <&gpiof 8 GPIO_ACTIVE_HIGH>;
257263
boot-rec-gpios = <&gpiof 6 GPIO_ACTIVE_HIGH>;
264+
power-domain = <&gnss_ldo_domain>;
258265
};
259266

260267
/* AMS Ambient Light Sensor */

drivers/power_domain/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
zephyr_library()
55

66
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_GPIO power_domain_gpio.c)
7+
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_REGULATOR power_domain_regulator.c)
78
zephyr_library_sources_ifdef(CONFIG_POWER_DOMAIN_INTEL_ADSP power_domain_intel_adsp.c)

drivers/power_domain/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
menuconfig POWER_DOMAIN
55
bool "Power domain drivers"
6+
default y if PM_DEVICE_POWER_DOMAIN
67
help
78
Include drivers for power domains in system config
89

@@ -26,4 +27,11 @@ config POWER_DOMAIN_INTEL_ADSP
2627
help
2728
Include Intel ADSP power domain control mechanisms
2829

30+
config POWER_DOMAIN_REGULATOR
31+
bool "Regulator controlled power domain"
32+
default y
33+
depends on DT_HAS_POWER_DOMAIN_REGULATOR_ENABLED
34+
depends on REGULATOR
35+
depends on TIMEOUT_64BIT
36+
2937
endif

drivers/power_domain/power_domain_gpio.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright (c) 2022, Commonwealth Scientific and Industrial Research
33
* Organisation (CSIRO) ABN 41 687 119 230.
4+
* Copyright (c) 2023 T-Mobile USA, Inc.
45
*
56
* SPDX-License-Identifier: Apache-2.0
67
*/
@@ -19,6 +20,7 @@ struct pd_gpio_config {
1920
struct gpio_dt_spec enable;
2021
uint32_t startup_delay_us;
2122
uint32_t off_on_delay_us;
23+
bool boot_on;
2224
};
2325

2426
struct pd_gpio_data {
@@ -116,6 +118,8 @@ static int pd_gpio_init(const struct device *dev)
116118
/* Device is unpowered */
117119
pm_device_init_off(dev);
118120
rc = gpio_pin_configure_dt(&cfg->enable, GPIO_DISCONNECTED);
121+
} else if (cfg->boot_on) {
122+
rc = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_ACTIVE);
119123
} else {
120124
pm_device_init_suspended(dev);
121125
rc = gpio_pin_configure_dt(&cfg->enable, GPIO_OUTPUT_INACTIVE);
@@ -129,6 +133,7 @@ static int pd_gpio_init(const struct device *dev)
129133
.enable = GPIO_DT_SPEC_INST_GET(id, enable_gpios), \
130134
.startup_delay_us = DT_INST_PROP(id, startup_delay_us), \
131135
.off_on_delay_us = DT_INST_PROP(id, off_on_delay_us), \
136+
.boot_on = DT_INST_PROP(id, boot_on), \
132137
}; \
133138
static struct pd_gpio_data pd_gpio_##id##_data; \
134139
PM_DEVICE_DT_INST_DEFINE(id, pd_gpio_pm_action); \
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright (c) 2022, Commonwealth Scientific and Industrial Research
3+
* Organisation (CSIRO) ABN 41 687 119 230.
4+
* Copyright (c) 2023 T-Mobile USA, Inc.
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
#define DT_DRV_COMPAT power_domain_regulator
9+
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/drivers/regulator.h>
12+
#include <zephyr/pm/device.h>
13+
#include <zephyr/pm/device_runtime.h>
14+
15+
#include <zephyr/logging/log.h>
16+
LOG_MODULE_REGISTER(power_domain_regulator, CONFIG_POWER_DOMAIN_LOG_LEVEL);
17+
18+
struct pd_reg_config {
19+
const struct device *regulator;
20+
uint32_t startup_delay_us;
21+
uint32_t off_on_delay_us;
22+
};
23+
24+
struct pd_reg_data {
25+
k_timeout_t next_boot;
26+
};
27+
28+
struct pd_visitor_context {
29+
const struct device *domain;
30+
enum pm_device_action action;
31+
};
32+
33+
static int pd_on_domain_visitor(const struct device *dev, void *context)
34+
{
35+
struct pd_visitor_context *visitor_context = context;
36+
37+
/* Only run action if the device is on the specified domain */
38+
if (!dev->pm || (dev->pm->domain != visitor_context->domain)) {
39+
return 0;
40+
}
41+
42+
(void)pm_device_action_run(dev, visitor_context->action);
43+
return 0;
44+
}
45+
46+
static int pd_reg_pm_action(const struct device *dev,
47+
enum pm_device_action action)
48+
{
49+
const struct pd_reg_config *cfg = dev->config;
50+
struct pd_reg_data *data = dev->data;
51+
struct pd_visitor_context context = {.domain = dev};
52+
int64_t next_boot_ticks;
53+
int rc = 0;
54+
55+
/* Validate that blocking API's can be used */
56+
if (!k_can_yield()) {
57+
LOG_ERR("Blocking actions cannot run in this context");
58+
return -ENOTSUP;
59+
}
60+
61+
switch (action) {
62+
case PM_DEVICE_ACTION_RESUME:
63+
/* Wait until we can boot again */
64+
k_sleep(data->next_boot);
65+
/* Switch power on */
66+
regulator_enable(cfg->regulator);
67+
LOG_INF("%s is now ON", dev->name);
68+
/* Wait for domain to come up */
69+
k_sleep(K_USEC(cfg->startup_delay_us));
70+
/* Notify devices on the domain they are now powered */
71+
context.action = PM_DEVICE_ACTION_TURN_ON;
72+
(void)device_supported_foreach(dev, pd_on_domain_visitor, &context);
73+
break;
74+
case PM_DEVICE_ACTION_SUSPEND:
75+
/* Notify devices on the domain that power is going down */
76+
context.action = PM_DEVICE_ACTION_TURN_OFF;
77+
(void)device_supported_foreach(dev, pd_on_domain_visitor, &context);
78+
/* Switch power off */
79+
regulator_disable(cfg->regulator);
80+
LOG_INF("%s is now OFF", dev->name);
81+
/* Store next time we can boot */
82+
next_boot_ticks = k_uptime_ticks() + k_us_to_ticks_ceil32(cfg->off_on_delay_us);
83+
data->next_boot = K_TIMEOUT_ABS_TICKS(next_boot_ticks);
84+
break;
85+
default:
86+
rc = -ENOTSUP;
87+
}
88+
89+
return rc;
90+
}
91+
92+
static int pd_reg_init(const struct device *dev)
93+
{
94+
const struct pd_reg_config *cfg = dev->config;
95+
struct pd_reg_data *data = dev->data;
96+
int rc = 0;
97+
98+
if (!device_is_ready(cfg->regulator)) {
99+
LOG_ERR("Regulator %s is not ready", cfg->regulator->name);
100+
return -ENODEV;
101+
}
102+
/* We can't know how long the domain has been off for before boot */
103+
data->next_boot = K_TIMEOUT_ABS_US(cfg->off_on_delay_us);
104+
105+
return rc;
106+
}
107+
108+
#define POWER_DOMAIN_DEVICE(id) \
109+
static const struct pd_reg_config pd_reg_##id##_cfg = { \
110+
.regulator = DEVICE_DT_GET(DT_PHANDLE(DT_DRV_INST(id), regulator)), \
111+
.startup_delay_us = DT_INST_PROP(id, startup_delay_us), \
112+
.off_on_delay_us = DT_INST_PROP(id, off_on_delay_us), \
113+
}; \
114+
static struct pd_reg_data pd_reg_##id##_data; \
115+
PM_DEVICE_DT_INST_DEFINE(id, pd_reg_pm_action); \
116+
DEVICE_DT_INST_DEFINE(id, pd_reg_init, PM_DEVICE_DT_INST_GET(id), \
117+
&pd_reg_##id##_data, &pd_reg_##id##_cfg, \
118+
POST_KERNEL, 75, \
119+
NULL);
120+
121+
DT_INST_FOREACH_STATUS_OKAY(POWER_DOMAIN_DEVICE)

0 commit comments

Comments
 (0)