]>
Commit | Line | Data |
---|---|---|
89c1e2da SW |
1 | /* |
2 | * Copyright (c) 2016, NVIDIA CORPORATION. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0 | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
8 | #include <dm.h> | |
9 | #include <fdtdec.h> | |
10 | #include <reset.h> | |
11 | #include <reset-uclass.h> | |
12 | ||
13 | DECLARE_GLOBAL_DATA_PTR; | |
14 | ||
15 | static inline struct reset_ops *reset_dev_ops(struct udevice *dev) | |
16 | { | |
17 | return (struct reset_ops *)dev->driver->ops; | |
18 | } | |
19 | ||
20 | static int reset_of_xlate_default(struct reset_ctl *reset_ctl, | |
40a475e8 | 21 | struct ofnode_phandle_args *args) |
89c1e2da SW |
22 | { |
23 | debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); | |
24 | ||
25 | if (args->args_count != 1) { | |
26 | debug("Invaild args_count: %d\n", args->args_count); | |
27 | return -EINVAL; | |
28 | } | |
29 | ||
30 | reset_ctl->id = args->args[0]; | |
31 | ||
32 | return 0; | |
33 | } | |
34 | ||
35 | int reset_get_by_index(struct udevice *dev, int index, | |
36 | struct reset_ctl *reset_ctl) | |
37 | { | |
40a475e8 | 38 | struct ofnode_phandle_args args; |
89c1e2da SW |
39 | int ret; |
40 | struct udevice *dev_reset; | |
41 | struct reset_ops *ops; | |
42 | ||
43 | debug("%s(dev=%p, index=%d, reset_ctl=%p)\n", __func__, dev, index, | |
44 | reset_ctl); | |
3b9d1bdd | 45 | reset_ctl->dev = NULL; |
89c1e2da | 46 | |
40a475e8 SG |
47 | ret = dev_read_phandle_with_args(dev, "resets", "#reset-cells", 0, |
48 | index, &args); | |
89c1e2da | 49 | if (ret) { |
40a475e8 | 50 | debug("%s: fdtdec_parse_phandle_with_args() failed: %d\n", |
89c1e2da SW |
51 | __func__, ret); |
52 | return ret; | |
53 | } | |
54 | ||
40a475e8 SG |
55 | ret = uclass_get_device_by_ofnode(UCLASS_RESET, args.node, |
56 | &dev_reset); | |
89c1e2da | 57 | if (ret) { |
40a475e8 | 58 | debug("%s: uclass_get_device_by_ofnode() failed: %d\n", |
89c1e2da | 59 | __func__, ret); |
40a475e8 | 60 | debug("%s %d\n", ofnode_get_name(args.node), args.args[0]); |
89c1e2da SW |
61 | return ret; |
62 | } | |
63 | ops = reset_dev_ops(dev_reset); | |
64 | ||
65 | reset_ctl->dev = dev_reset; | |
66 | if (ops->of_xlate) | |
67 | ret = ops->of_xlate(reset_ctl, &args); | |
68 | else | |
69 | ret = reset_of_xlate_default(reset_ctl, &args); | |
70 | if (ret) { | |
71 | debug("of_xlate() failed: %d\n", ret); | |
72 | return ret; | |
73 | } | |
74 | ||
75 | ret = ops->request(reset_ctl); | |
76 | if (ret) { | |
77 | debug("ops->request() failed: %d\n", ret); | |
78 | return ret; | |
79 | } | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
84 | int reset_get_by_name(struct udevice *dev, const char *name, | |
85 | struct reset_ctl *reset_ctl) | |
86 | { | |
87 | int index; | |
88 | ||
89 | debug("%s(dev=%p, name=%s, reset_ctl=%p)\n", __func__, dev, name, | |
90 | reset_ctl); | |
3b9d1bdd | 91 | reset_ctl->dev = NULL; |
89c1e2da | 92 | |
40a475e8 | 93 | index = dev_read_stringlist_search(dev, "reset-names", name); |
89c1e2da | 94 | if (index < 0) { |
b02e4044 | 95 | debug("fdt_stringlist_search() failed: %d\n", index); |
89c1e2da SW |
96 | return index; |
97 | } | |
98 | ||
99 | return reset_get_by_index(dev, index, reset_ctl); | |
100 | } | |
101 | ||
9bd5cdf6 PC |
102 | int reset_request(struct reset_ctl *reset_ctl) |
103 | { | |
104 | struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); | |
105 | ||
106 | debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); | |
107 | ||
108 | return ops->request(reset_ctl); | |
109 | } | |
110 | ||
89c1e2da SW |
111 | int reset_free(struct reset_ctl *reset_ctl) |
112 | { | |
113 | struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); | |
114 | ||
115 | debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); | |
116 | ||
117 | return ops->free(reset_ctl); | |
118 | } | |
119 | ||
120 | int reset_assert(struct reset_ctl *reset_ctl) | |
121 | { | |
122 | struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); | |
123 | ||
124 | debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); | |
125 | ||
126 | return ops->rst_assert(reset_ctl); | |
127 | } | |
128 | ||
129 | int reset_deassert(struct reset_ctl *reset_ctl) | |
130 | { | |
131 | struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); | |
132 | ||
133 | debug("%s(reset_ctl=%p)\n", __func__, reset_ctl); | |
134 | ||
135 | return ops->rst_deassert(reset_ctl); | |
136 | } | |
137 | ||
3b9d1bdd PC |
138 | int reset_release_all(struct reset_ctl *reset_ctl, int count) |
139 | { | |
140 | int i, ret; | |
141 | ||
142 | for (i = 0; i < count; i++) { | |
143 | debug("%s(reset_ctl[%d]=%p)\n", __func__, i, &reset_ctl[i]); | |
144 | ||
145 | /* check if reset has been previously requested */ | |
146 | if (!reset_ctl[i].dev) | |
147 | continue; | |
148 | ||
149 | ret = reset_assert(&reset_ctl[i]); | |
150 | if (ret) | |
151 | return ret; | |
152 | ||
153 | ret = reset_free(&reset_ctl[i]); | |
154 | if (ret) | |
155 | return ret; | |
156 | } | |
157 | ||
158 | return 0; | |
159 | } | |
160 | ||
89c1e2da SW |
161 | UCLASS_DRIVER(reset) = { |
162 | .id = UCLASS_RESET, | |
163 | .name = "reset", | |
164 | }; |