sunxi: initial 4.4 support
[openwrt/openwrt.git] / target / linux / sunxi / patches-4.4 / 143-reset-add-shared-resetcontrol-asserts.patch
1 From d25cfe9b4f9663216ce4e011e3f1e7fa669ab58a Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Fri, 27 Nov 2015 21:09:05 +0100
4 Subject: [PATCH] reset: Add shared reset_control_[de]assert variants
5
6 Add reset_control_deassert_shared / reset_control_assert_shared
7 functions which are intended for use by drivers for hw blocks which
8 (may) share a reset line with another driver / hw block.
9
10 Unlike the regular reset_control_[de]assert functions these functions
11 keep track of how often deassert_shared / assert_shared have been called
12 and keep the line deasserted as long as deassert has been called more
13 times than assert.
14
15 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
16 ---
17 Changes in v2:
18 -This is a new patch in v2 of this patch-set
19 ---
20 drivers/reset/core.c | 121 ++++++++++++++++++++++++++++++++++++---
21 include/linux/reset-controller.h | 2 +
22 include/linux/reset.h | 2 +
23 3 files changed, 116 insertions(+), 9 deletions(-)
24
25 diff --git a/drivers/reset/core.c b/drivers/reset/core.c
26 index 9ab9290..8c3436c 100644
27 --- a/drivers/reset/core.c
28 +++ b/drivers/reset/core.c
29 @@ -22,16 +22,29 @@ static DEFINE_MUTEX(reset_controller_list_mutex);
30 static LIST_HEAD(reset_controller_list);
31
32 /**
33 + * struct reset_line - a reset line
34 + * @list: list entry for the reset controllers reset line list
35 + * @id: ID of the reset line in the reset controller device
36 + * @refcnt: Number of reset_control structs referencing this device
37 + * @deassert_cnt: Number of times this reset line has been deasserted
38 + */
39 +struct reset_line {
40 + struct list_head list;
41 + unsigned int id;
42 + unsigned int refcnt;
43 + unsigned int deassert_cnt;
44 +};
45 +
46 +/**
47 * struct reset_control - a reset control
48 * @rcdev: a pointer to the reset controller device
49 * this reset control belongs to
50 - * @id: ID of the reset controller in the reset
51 - * controller device
52 + * @line: reset line for this reset control
53 */
54 struct reset_control {
55 struct reset_controller_dev *rcdev;
56 + struct reset_line *line;
57 struct device *dev;
58 - unsigned int id;
59 };
60
61 /**
62 @@ -66,6 +79,8 @@ int reset_controller_register(struct reset_controller_dev *rcdev)
63 rcdev->of_xlate = of_reset_simple_xlate;
64 }
65
66 + INIT_LIST_HEAD(&rcdev->reset_line_head);
67 +
68 mutex_lock(&reset_controller_list_mutex);
69 list_add(&rcdev->list, &reset_controller_list);
70 mutex_unlock(&reset_controller_list_mutex);
71 @@ -93,7 +108,7 @@ EXPORT_SYMBOL_GPL(reset_controller_unregister);
72 int reset_control_reset(struct reset_control *rstc)
73 {
74 if (rstc->rcdev->ops->reset)
75 - return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
76 + return rstc->rcdev->ops->reset(rstc->rcdev, rstc->line->id);
77
78 return -ENOTSUPP;
79 }
80 @@ -106,7 +121,7 @@ EXPORT_SYMBOL_GPL(reset_control_reset);
81 int reset_control_assert(struct reset_control *rstc)
82 {
83 if (rstc->rcdev->ops->assert)
84 - return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
85 + return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
86
87 return -ENOTSUPP;
88 }
89 @@ -119,13 +134,55 @@ EXPORT_SYMBOL_GPL(reset_control_assert);
90 int reset_control_deassert(struct reset_control *rstc)
91 {
92 if (rstc->rcdev->ops->deassert)
93 - return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
94 + return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
95
96 return -ENOTSUPP;
97 }
98 EXPORT_SYMBOL_GPL(reset_control_deassert);
99
100 /**
101 + * reset_control_assert_shared - asserts a shared reset line
102 + * @rstc: reset controller
103 + *
104 + * Assert a shared reset line, this functions decreases the deassert count
105 + * of the line by one and asserts it if, and only if, the deassert count
106 + * reaches 0.
107 + */
108 +int reset_control_assert_shared(struct reset_control *rstc)
109 +{
110 + if (!rstc->rcdev->ops->assert)
111 + return -ENOTSUPP;
112 +
113 + rstc->line->deassert_cnt--;
114 + if (rstc->line->deassert_cnt)
115 + return 0;
116 +
117 + return rstc->rcdev->ops->assert(rstc->rcdev, rstc->line->id);
118 +}
119 +EXPORT_SYMBOL_GPL(reset_control_assert_shared);
120 +
121 +/**
122 + * reset_control_deassert_shared - deasserts a shared reset line
123 + * @rstc: reset controller
124 + *
125 + * Assert a shared reset line, this functions increases the deassert count
126 + * of the line by one and deasserts the reset line (if it was not already
127 + * deasserted).
128 + */
129 +int reset_control_deassert_shared(struct reset_control *rstc)
130 +{
131 + if (!rstc->rcdev->ops->deassert)
132 + return -ENOTSUPP;
133 +
134 + rstc->line->deassert_cnt++;
135 + if (rstc->line->deassert_cnt != 1)
136 + return 0;
137 +
138 + return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->line->id);
139 +}
140 +EXPORT_SYMBOL_GPL(reset_control_deassert_shared);
141 +
142 +/**
143 * reset_control_status - returns a negative errno if not supported, a
144 * positive value if the reset line is asserted, or zero if the reset
145 * line is not asserted.
146 @@ -134,12 +191,47 @@ EXPORT_SYMBOL_GPL(reset_control_deassert);
147 int reset_control_status(struct reset_control *rstc)
148 {
149 if (rstc->rcdev->ops->status)
150 - return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
151 + return rstc->rcdev->ops->status(rstc->rcdev, rstc->line->id);
152
153 return -ENOTSUPP;
154 }
155 EXPORT_SYMBOL_GPL(reset_control_status);
156
157 +static struct reset_line *reset_line_get(struct reset_controller_dev *rcdev,
158 + unsigned int index)
159 +{
160 + struct reset_line *line;
161 +
162 + list_for_each_entry(line, &rcdev->reset_line_head, list) {
163 + if (line->id == index) {
164 + line->refcnt++;
165 + return line;
166 + }
167 + }
168 +
169 + line = kzalloc(sizeof(*line), GFP_KERNEL);
170 + if (!line)
171 + return NULL;
172 +
173 + list_add(&line->list, &rcdev->reset_line_head);
174 + line->id = index;
175 + line->refcnt = 1;
176 +
177 + return line;
178 +}
179 +
180 +static void reset_line_put(struct reset_line *line)
181 +{
182 + if (!line)
183 + return;
184 +
185 + if (--line->refcnt)
186 + return;
187 +
188 + list_del(&line->list);
189 + kfree(line);
190 +}
191 +
192 /**
193 * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
194 * controller by index.
195 @@ -155,6 +247,7 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
196 {
197 struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
198 struct reset_controller_dev *r, *rcdev;
199 + struct reset_line *line;
200 struct of_phandle_args args;
201 int rstc_id;
202 int ret;
203 @@ -186,16 +279,22 @@ struct reset_control *of_reset_control_get_by_index(struct device_node *node,
204 }
205
206 try_module_get(rcdev->owner);
207 +
208 + /* reset_controller_list_mutex also protects the reset_line list */
209 + line = reset_line_get(rcdev, rstc_id);
210 +
211 mutex_unlock(&reset_controller_list_mutex);
212
213 rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
214 - if (!rstc) {
215 + if (!line || !rstc) {
216 + kfree(rstc);
217 + reset_line_put(line);
218 module_put(rcdev->owner);
219 return ERR_PTR(-ENOMEM);
220 }
221
222 rstc->rcdev = rcdev;
223 - rstc->id = rstc_id;
224 + rstc->line = line;
225
226 return rstc;
227 }
228 @@ -259,6 +358,10 @@ void reset_control_put(struct reset_control *rstc)
229 if (IS_ERR(rstc))
230 return;
231
232 + mutex_lock(&reset_controller_list_mutex);
233 + reset_line_put(rstc->line);
234 + mutex_unlock(&reset_controller_list_mutex);
235 +
236 module_put(rstc->rcdev->owner);
237 kfree(rstc);
238 }
239 diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
240 index ce6b962..7f2cbd1 100644
241 --- a/include/linux/reset-controller.h
242 +++ b/include/linux/reset-controller.h
243 @@ -31,6 +31,7 @@ struct of_phandle_args;
244 * @ops: a pointer to device specific struct reset_control_ops
245 * @owner: kernel module of the reset controller driver
246 * @list: internal list of reset controller devices
247 + * @reset_line_head: head of internal list of reset lines
248 * @of_node: corresponding device tree node as phandle target
249 * @of_reset_n_cells: number of cells in reset line specifiers
250 * @of_xlate: translation function to translate from specifier as found in the
251 @@ -41,6 +42,7 @@ struct reset_controller_dev {
252 struct reset_control_ops *ops;
253 struct module *owner;
254 struct list_head list;
255 + struct list_head reset_line_head;
256 struct device_node *of_node;
257 int of_reset_n_cells;
258 int (*of_xlate)(struct reset_controller_dev *rcdev,
259 diff --git a/include/linux/reset.h b/include/linux/reset.h
260 index c4c097d..1cca8ce 100644
261 --- a/include/linux/reset.h
262 +++ b/include/linux/reset.h
263 @@ -11,6 +11,8 @@ int reset_control_reset(struct reset_control *rstc);
264 int reset_control_assert(struct reset_control *rstc);
265 int reset_control_deassert(struct reset_control *rstc);
266 int reset_control_status(struct reset_control *rstc);
267 +int reset_control_assert_shared(struct reset_control *rstc);
268 +int reset_control_deassert_shared(struct reset_control *rstc);
269
270 struct reset_control *reset_control_get(struct device *dev, const char *id);
271 void reset_control_put(struct reset_control *rstc);