1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2014 MediaTek Inc. |
4 | */ |
5 | |
6 | #include <linux/mfd/syscon.h> |
7 | #include <linux/module.h> |
8 | #include <linux/of.h> |
9 | #include <linux/platform_device.h> |
10 | #include <linux/regmap.h> |
11 | #include <linux/slab.h> |
12 | |
13 | #include "reset.h" |
14 | |
15 | static inline struct mtk_clk_rst_data *to_mtk_clk_rst_data(struct reset_controller_dev *rcdev) |
16 | { |
17 | return container_of(rcdev, struct mtk_clk_rst_data, rcdev); |
18 | } |
19 | |
20 | static int mtk_reset_update(struct reset_controller_dev *rcdev, |
21 | unsigned long id, bool deassert) |
22 | { |
23 | struct mtk_clk_rst_data *data = to_mtk_clk_rst_data(rcdev); |
24 | unsigned int val = deassert ? 0 : ~0; |
25 | |
26 | return regmap_update_bits(map: data->regmap, |
27 | reg: data->desc->rst_bank_ofs[id / RST_NR_PER_BANK], |
28 | BIT(id % RST_NR_PER_BANK), val); |
29 | } |
30 | |
31 | static int mtk_reset_assert(struct reset_controller_dev *rcdev, |
32 | unsigned long id) |
33 | { |
34 | return mtk_reset_update(rcdev, id, deassert: false); |
35 | } |
36 | |
37 | static int mtk_reset_deassert(struct reset_controller_dev *rcdev, |
38 | unsigned long id) |
39 | { |
40 | return mtk_reset_update(rcdev, id, deassert: true); |
41 | } |
42 | |
43 | static int mtk_reset(struct reset_controller_dev *rcdev, unsigned long id) |
44 | { |
45 | int ret; |
46 | |
47 | ret = mtk_reset_assert(rcdev, id); |
48 | if (ret) |
49 | return ret; |
50 | |
51 | return mtk_reset_deassert(rcdev, id); |
52 | } |
53 | |
54 | static int mtk_reset_update_set_clr(struct reset_controller_dev *rcdev, |
55 | unsigned long id, bool deassert) |
56 | { |
57 | struct mtk_clk_rst_data *data = to_mtk_clk_rst_data(rcdev); |
58 | unsigned int deassert_ofs = deassert ? 0x4 : 0; |
59 | |
60 | return regmap_write(map: data->regmap, |
61 | reg: data->desc->rst_bank_ofs[id / RST_NR_PER_BANK] + |
62 | deassert_ofs, |
63 | BIT(id % RST_NR_PER_BANK)); |
64 | } |
65 | |
66 | static int mtk_reset_assert_set_clr(struct reset_controller_dev *rcdev, |
67 | unsigned long id) |
68 | { |
69 | return mtk_reset_update_set_clr(rcdev, id, deassert: false); |
70 | } |
71 | |
72 | static int mtk_reset_deassert_set_clr(struct reset_controller_dev *rcdev, |
73 | unsigned long id) |
74 | { |
75 | return mtk_reset_update_set_clr(rcdev, id, deassert: true); |
76 | } |
77 | |
78 | static int mtk_reset_set_clr(struct reset_controller_dev *rcdev, |
79 | unsigned long id) |
80 | { |
81 | int ret; |
82 | |
83 | ret = mtk_reset_assert_set_clr(rcdev, id); |
84 | if (ret) |
85 | return ret; |
86 | return mtk_reset_deassert_set_clr(rcdev, id); |
87 | } |
88 | |
89 | static const struct reset_control_ops mtk_reset_ops = { |
90 | .assert = mtk_reset_assert, |
91 | .deassert = mtk_reset_deassert, |
92 | .reset = mtk_reset, |
93 | }; |
94 | |
95 | static const struct reset_control_ops mtk_reset_ops_set_clr = { |
96 | .assert = mtk_reset_assert_set_clr, |
97 | .deassert = mtk_reset_deassert_set_clr, |
98 | .reset = mtk_reset_set_clr, |
99 | }; |
100 | |
101 | static int reset_xlate(struct reset_controller_dev *rcdev, |
102 | const struct of_phandle_args *reset_spec) |
103 | { |
104 | struct mtk_clk_rst_data *data = to_mtk_clk_rst_data(rcdev); |
105 | |
106 | if (reset_spec->args[0] >= rcdev->nr_resets || |
107 | reset_spec->args[0] >= data->desc->rst_idx_map_nr) |
108 | return -EINVAL; |
109 | |
110 | return data->desc->rst_idx_map[reset_spec->args[0]]; |
111 | } |
112 | |
113 | int mtk_register_reset_controller(struct device_node *np, |
114 | const struct mtk_clk_rst_desc *desc) |
115 | { |
116 | struct regmap *regmap; |
117 | const struct reset_control_ops *rcops = NULL; |
118 | struct mtk_clk_rst_data *data; |
119 | int ret; |
120 | |
121 | if (!desc) { |
122 | pr_err("mtk clock reset desc is NULL\n" ); |
123 | return -EINVAL; |
124 | } |
125 | |
126 | switch (desc->version) { |
127 | case MTK_RST_SIMPLE: |
128 | rcops = &mtk_reset_ops; |
129 | break; |
130 | case MTK_RST_SET_CLR: |
131 | rcops = &mtk_reset_ops_set_clr; |
132 | break; |
133 | default: |
134 | pr_err("Unknown reset version %d\n" , desc->version); |
135 | return -EINVAL; |
136 | } |
137 | |
138 | regmap = device_node_to_regmap(np); |
139 | if (IS_ERR(ptr: regmap)) { |
140 | pr_err("Cannot find regmap for %pOF: %pe\n" , np, regmap); |
141 | return -EINVAL; |
142 | } |
143 | |
144 | data = kzalloc(size: sizeof(*data), GFP_KERNEL); |
145 | if (!data) |
146 | return -ENOMEM; |
147 | |
148 | data->desc = desc; |
149 | data->regmap = regmap; |
150 | data->rcdev.owner = THIS_MODULE; |
151 | data->rcdev.ops = rcops; |
152 | data->rcdev.of_node = np; |
153 | |
154 | if (data->desc->rst_idx_map_nr > 0) { |
155 | data->rcdev.of_reset_n_cells = 1; |
156 | data->rcdev.nr_resets = desc->rst_idx_map_nr; |
157 | data->rcdev.of_xlate = reset_xlate; |
158 | } else { |
159 | data->rcdev.nr_resets = desc->rst_bank_nr * RST_NR_PER_BANK; |
160 | } |
161 | |
162 | ret = reset_controller_register(rcdev: &data->rcdev); |
163 | if (ret) { |
164 | pr_err("could not register reset controller: %d\n" , ret); |
165 | kfree(objp: data); |
166 | return ret; |
167 | } |
168 | |
169 | return 0; |
170 | } |
171 | |
172 | int mtk_register_reset_controller_with_dev(struct device *dev, |
173 | const struct mtk_clk_rst_desc *desc) |
174 | { |
175 | struct device_node *np = dev->of_node; |
176 | struct regmap *regmap; |
177 | const struct reset_control_ops *rcops = NULL; |
178 | struct mtk_clk_rst_data *data; |
179 | int ret; |
180 | |
181 | if (!desc) { |
182 | dev_err(dev, "mtk clock reset desc is NULL\n" ); |
183 | return -EINVAL; |
184 | } |
185 | |
186 | switch (desc->version) { |
187 | case MTK_RST_SIMPLE: |
188 | rcops = &mtk_reset_ops; |
189 | break; |
190 | case MTK_RST_SET_CLR: |
191 | rcops = &mtk_reset_ops_set_clr; |
192 | break; |
193 | default: |
194 | dev_err(dev, "Unknown reset version %d\n" , desc->version); |
195 | return -EINVAL; |
196 | } |
197 | |
198 | regmap = device_node_to_regmap(np); |
199 | if (IS_ERR(ptr: regmap)) { |
200 | dev_err(dev, "Cannot find regmap %pe\n" , regmap); |
201 | return -EINVAL; |
202 | } |
203 | |
204 | data = devm_kzalloc(dev, size: sizeof(*data), GFP_KERNEL); |
205 | if (!data) |
206 | return -ENOMEM; |
207 | |
208 | data->desc = desc; |
209 | data->regmap = regmap; |
210 | data->rcdev.owner = THIS_MODULE; |
211 | data->rcdev.ops = rcops; |
212 | data->rcdev.of_node = np; |
213 | data->rcdev.dev = dev; |
214 | |
215 | if (data->desc->rst_idx_map_nr > 0) { |
216 | data->rcdev.of_reset_n_cells = 1; |
217 | data->rcdev.nr_resets = desc->rst_idx_map_nr; |
218 | data->rcdev.of_xlate = reset_xlate; |
219 | } else { |
220 | data->rcdev.nr_resets = desc->rst_bank_nr * RST_NR_PER_BANK; |
221 | } |
222 | |
223 | ret = devm_reset_controller_register(dev, rcdev: &data->rcdev); |
224 | if (ret) { |
225 | dev_err(dev, "could not register reset controller: %d\n" , ret); |
226 | return ret; |
227 | } |
228 | |
229 | return 0; |
230 | } |
231 | EXPORT_SYMBOL_GPL(mtk_register_reset_controller_with_dev); |
232 | |
233 | MODULE_LICENSE("GPL" ); |
234 | |