diff options
author | Simon Glass <sjg@chromium.org> | 2020-07-07 13:12:02 -0600 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2020-07-17 14:32:24 +0800 |
commit | 740630ba73768667a2f87326f2a237d373a5093d (patch) | |
tree | 65f543df914a485cc6f0ce3e5ebdeaaa34559fcc /lib/acpi | |
parent | f8054dd8ba533be0e2ebd7965b95446a1f573953 (diff) | |
download | u-boot-740630ba73768667a2f87326f2a237d373a5093d.tar.gz u-boot-740630ba73768667a2f87326f2a237d373a5093d.tar.bz2 u-boot-740630ba73768667a2f87326f2a237d373a5093d.zip |
acpi: Add support for a generic power sequence
Add a way for devices to enable and disable themselves using ACPI code
that updates GPIOs. This takes several timing parameters and supports
enable, reset and stop.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Wolfgang Wallner <wolfgang.wallner@br-automation.com>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'lib/acpi')
-rw-r--r-- | lib/acpi/acpi_device.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/lib/acpi/acpi_device.c b/lib/acpi/acpi_device.c index b628fa1337..c66cafcfee 100644 --- a/lib/acpi/acpi_device.c +++ b/lib/acpi/acpi_device.c @@ -386,6 +386,105 @@ int acpi_device_write_interrupt_or_gpio(struct acpi_ctx *ctx, return pin; } +/* PowerResource() with Enable and/or Reset control */ +int acpi_device_add_power_res(struct acpi_ctx *ctx, u32 tx_state_val, + const char *dw0_read, const char *dw0_write, + const struct gpio_desc *reset_gpio, + uint reset_delay_ms, uint reset_off_delay_ms, + const struct gpio_desc *enable_gpio, + uint enable_delay_ms, uint enable_off_delay_ms, + const struct gpio_desc *stop_gpio, + uint stop_delay_ms, uint stop_off_delay_ms) +{ + static const char *const power_res_dev_states[] = { "_PR0", "_PR3" }; + struct acpi_gpio reset, enable, stop; + bool has_reset, has_enable, has_stop; + int ret; + + gpio_get_acpi(reset_gpio, &reset); + gpio_get_acpi(enable_gpio, &enable); + gpio_get_acpi(stop_gpio, &stop); + has_reset = reset.pins[0]; + has_enable = enable.pins[0]; + has_stop = stop.pins[0]; + + if (!has_reset && !has_enable && !has_stop) + return -EINVAL; + + /* PowerResource (PRIC, 0, 0) */ + acpigen_write_power_res(ctx, "PRIC", 0, 0, power_res_dev_states, + ARRAY_SIZE(power_res_dev_states)); + + /* Method (_STA, 0, NotSerialized) { Return (0x1) } */ + acpigen_write_sta(ctx, 0x1); + + /* Method (_ON, 0, Serialized) */ + acpigen_write_method_serialized(ctx, "_ON", 0); + if (reset_gpio) { + ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_read, + dw0_write, &reset, true); + if (ret) + return log_msg_ret("reset1", ret); + } + if (has_enable) { + ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_read, + dw0_write, &enable, true); + if (ret) + return log_msg_ret("enable1", ret); + if (enable_delay_ms) + acpigen_write_sleep(ctx, enable_delay_ms); + } + if (has_reset) { + ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_read, + dw0_write, &reset, false); + if (ret) + return log_msg_ret("reset2", ret); + if (reset_delay_ms) + acpigen_write_sleep(ctx, reset_delay_ms); + } + if (has_stop) { + ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_read, + dw0_write, &stop, false); + if (ret) + return log_msg_ret("stop1", ret); + if (stop_delay_ms) + acpigen_write_sleep(ctx, stop_delay_ms); + } + acpigen_pop_len(ctx); /* _ON method */ + + /* Method (_OFF, 0, Serialized) */ + acpigen_write_method_serialized(ctx, "_OFF", 0); + if (has_stop) { + ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_read, + dw0_write, &stop, true); + if (ret) + return log_msg_ret("stop2", ret); + if (stop_off_delay_ms) + acpigen_write_sleep(ctx, stop_off_delay_ms); + } + if (has_reset) { + ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_read, + dw0_write, &reset, true); + if (ret) + return log_msg_ret("reset3", ret); + if (reset_off_delay_ms) + acpigen_write_sleep(ctx, reset_off_delay_ms); + } + if (has_enable) { + ret = acpigen_set_enable_tx_gpio(ctx, tx_state_val, dw0_read, + dw0_write, &enable, false); + if (ret) + return log_msg_ret("enable2", ret); + if (enable_off_delay_ms) + acpigen_write_sleep(ctx, enable_off_delay_ms); + } + acpigen_pop_len(ctx); /* _OFF method */ + + acpigen_pop_len(ctx); /* PowerResource PRIC */ + + return 0; +} + /* ACPI 6.3 section 6.4.3.8.2.1 - I2cSerialBus() */ static void acpi_device_write_i2c(struct acpi_ctx *ctx, const struct acpi_i2c *i2c) |