| /* |
| * Copyright (c) 2022 ASPEED Technology Inc. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #define DT_DRV_COMPAT aspeed_ast10x0_reset |
| #include <errno.h> |
| #include <zephyr/dt-bindings/reset/ast10x0_reset.h> |
| #include <zephyr/drivers/reset.h> |
| #include <zephyr/drivers/syscon.h> |
| #include <zephyr/sys/util.h> |
| |
| |
| /* |
| * RESET_CTRL0/1_ASSERT registers: |
| * - Each bit in these registers controls a reset line |
| * - Write '1' to a bit: assert the corresponding reset line |
| * - Write '0' to a bit: no effect |
| * RESET_CTRL0/1_DEASSERT register: |
| * - Write '1' to a bit: clear the corresponding bit in RESET_CTRL0/1_ASSERT. |
| * (deassert the corresponding reset line) |
| */ |
| #define RESET_CTRL0_ASSERT 0x40 |
| #define RESET_CTRL0_DEASSERT 0x44 |
| #define RESET_CTRL1_ASSERT 0x50 |
| #define RESET_CTRL1_DEASSERT 0x54 |
| |
| struct reset_aspeed_config { |
| const struct device *syscon; |
| }; |
| |
| static int aspeed_reset_line_assert(const struct device *dev, uint32_t id) |
| { |
| const struct reset_aspeed_config *config = dev->config; |
| const struct device *syscon = config->syscon; |
| uint32_t addr = RESET_CTRL0_ASSERT; |
| |
| if (id >= ASPEED_RESET_GRP_1_OFFSET) { |
| id -= ASPEED_RESET_GRP_1_OFFSET; |
| addr = RESET_CTRL1_ASSERT; |
| } |
| |
| return syscon_write_reg(syscon, addr, BIT(id)); |
| } |
| |
| static int aspeed_reset_line_deassert(const struct device *dev, uint32_t id) |
| { |
| const struct reset_aspeed_config *config = dev->config; |
| const struct device *syscon = config->syscon; |
| uint32_t addr = RESET_CTRL0_DEASSERT; |
| |
| if (id >= ASPEED_RESET_GRP_1_OFFSET) { |
| id -= ASPEED_RESET_GRP_1_OFFSET; |
| addr = RESET_CTRL1_DEASSERT; |
| } |
| |
| return syscon_write_reg(syscon, addr, BIT(id)); |
| } |
| |
| static int aspeed_reset_status(const struct device *dev, uint32_t id, uint8_t *status) |
| { |
| const struct reset_aspeed_config *config = dev->config; |
| const struct device *syscon = config->syscon; |
| uint32_t addr = RESET_CTRL0_ASSERT; |
| uint32_t reg_value; |
| int ret; |
| |
| if (id >= ASPEED_RESET_GRP_1_OFFSET) { |
| id -= ASPEED_RESET_GRP_1_OFFSET; |
| addr = RESET_CTRL1_ASSERT; |
| } |
| |
| ret = syscon_read_reg(syscon, addr, ®_value); |
| if (ret == 0) { |
| *status = !!(reg_value & BIT(id)); |
| } |
| |
| return ret; |
| } |
| |
| static int aspeed_reset_line_toggle(const struct device *dev, uint32_t id) |
| { |
| int ret; |
| |
| ret = aspeed_reset_line_assert(dev, id); |
| if (ret == 0) { |
| ret = aspeed_reset_line_deassert(dev, id); |
| } |
| |
| return ret; |
| } |
| |
| static int aspeed_reset_control_init(const struct device *dev) |
| { |
| ARG_UNUSED(dev); |
| return 0; |
| } |
| |
| static const struct reset_driver_api aspeed_reset_api = { |
| .status = aspeed_reset_status, |
| .line_assert = aspeed_reset_line_assert, |
| .line_deassert = aspeed_reset_line_deassert, |
| .line_toggle = aspeed_reset_line_toggle |
| }; |
| |
| #define ASPEED_RESET_INIT(n) \ |
| static const struct reset_aspeed_config reset_aspeed_cfg_##n = { \ |
| .syscon = DEVICE_DT_GET(DT_NODELABEL(syscon)), \ |
| }; \ |
| DEVICE_DT_INST_DEFINE(n, &aspeed_reset_control_init, NULL, NULL, &reset_aspeed_cfg_##n, \ |
| PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ |
| &aspeed_reset_api); |
| |
| DT_INST_FOREACH_STATUS_OKAY(ASPEED_RESET_INIT) |