1 /*
2  * Copyright (c) 2022 ASPEED Technology Inc.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT aspeed_ast10x0_reset
8 #include <errno.h>
9 #include <zephyr/dt-bindings/reset/ast10x0_reset.h>
10 #include <zephyr/drivers/reset.h>
11 #include <zephyr/drivers/syscon.h>
12 #include <zephyr/sys/util.h>
13 
14 
15 /*
16  * RESET_CTRL0/1_ASSERT registers:
17  *   - Each bit in these registers controls a reset line
18  *   - Write '1' to a bit: assert the corresponding reset line
19  *   - Write '0' to a bit: no effect
20  * RESET_CTRL0/1_DEASSERT register:
21  *   - Write '1' to a bit: clear the corresponding bit in RESET_CTRL0/1_ASSERT.
22  *                         (deassert the corresponding reset line)
23  */
24 #define RESET_CTRL0_ASSERT		0x40
25 #define RESET_CTRL0_DEASSERT		0x44
26 #define RESET_CTRL1_ASSERT		0x50
27 #define RESET_CTRL1_DEASSERT		0x54
28 
29 struct reset_aspeed_config {
30 	const struct device *syscon;
31 };
32 
aspeed_reset_line_assert(const struct device * dev,uint32_t id)33 static int aspeed_reset_line_assert(const struct device *dev, uint32_t id)
34 {
35 	const struct reset_aspeed_config *config = dev->config;
36 	const struct device *syscon = config->syscon;
37 	uint32_t addr = RESET_CTRL0_ASSERT;
38 
39 	if (id >= ASPEED_RESET_GRP_1_OFFSET) {
40 		id -= ASPEED_RESET_GRP_1_OFFSET;
41 		addr = RESET_CTRL1_ASSERT;
42 	}
43 
44 	return syscon_write_reg(syscon, addr, BIT(id));
45 }
46 
aspeed_reset_line_deassert(const struct device * dev,uint32_t id)47 static int aspeed_reset_line_deassert(const struct device *dev, uint32_t id)
48 {
49 	const struct reset_aspeed_config *config = dev->config;
50 	const struct device *syscon = config->syscon;
51 	uint32_t addr = RESET_CTRL0_DEASSERT;
52 
53 	if (id >= ASPEED_RESET_GRP_1_OFFSET) {
54 		id -= ASPEED_RESET_GRP_1_OFFSET;
55 		addr = RESET_CTRL1_DEASSERT;
56 	}
57 
58 	return syscon_write_reg(syscon, addr, BIT(id));
59 }
60 
aspeed_reset_status(const struct device * dev,uint32_t id,uint8_t * status)61 static int aspeed_reset_status(const struct device *dev, uint32_t id, uint8_t *status)
62 {
63 	const struct reset_aspeed_config *config = dev->config;
64 	const struct device *syscon = config->syscon;
65 	uint32_t addr = RESET_CTRL0_ASSERT;
66 	uint32_t reg_value;
67 	int ret;
68 
69 	if (id >= ASPEED_RESET_GRP_1_OFFSET) {
70 		id -= ASPEED_RESET_GRP_1_OFFSET;
71 		addr = RESET_CTRL1_ASSERT;
72 	}
73 
74 	ret = syscon_read_reg(syscon, addr, &reg_value);
75 	if (ret == 0) {
76 		*status = !!(reg_value & BIT(id));
77 	}
78 
79 	return ret;
80 }
81 
aspeed_reset_line_toggle(const struct device * dev,uint32_t id)82 static int aspeed_reset_line_toggle(const struct device *dev, uint32_t id)
83 {
84 	int ret;
85 
86 	ret = aspeed_reset_line_assert(dev, id);
87 	if (ret == 0) {
88 		ret = aspeed_reset_line_deassert(dev, id);
89 	}
90 
91 	return ret;
92 }
93 
94 static const struct reset_driver_api aspeed_reset_api = {
95 	.status = aspeed_reset_status,
96 	.line_assert = aspeed_reset_line_assert,
97 	.line_deassert = aspeed_reset_line_deassert,
98 	.line_toggle = aspeed_reset_line_toggle
99 };
100 
101 #define ASPEED_RESET_INIT(n)                                                                       \
102 	static const struct reset_aspeed_config reset_aspeed_cfg_##n = {                           \
103 		.syscon = DEVICE_DT_GET(DT_NODELABEL(syscon)),                                     \
104 	};                                                                                         \
105 	DEVICE_DT_INST_DEFINE(n, NULL, NULL, NULL, &reset_aspeed_cfg_##n,                          \
106 			      PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,                    \
107 			      &aspeed_reset_api);
108 
109 DT_INST_FOREACH_STATUS_OKAY(ASPEED_RESET_INIT)
110