Blame view

drivers/reset/core.c 7.96 KB
61fc41317   Philipp Zabel   reset: Add reset ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
  /*
   * Reset Controller framework
   *
   * Copyright 2013 Philipp Zabel, Pengutronix
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   */
  #include <linux/device.h>
  #include <linux/err.h>
  #include <linux/export.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/of.h>
  #include <linux/reset.h>
  #include <linux/reset-controller.h>
  #include <linux/slab.h>
  
  static DEFINE_MUTEX(reset_controller_list_mutex);
  static LIST_HEAD(reset_controller_list);
  
  /**
   * struct reset_control - a reset control
   * @rcdev: a pointer to the reset controller device
   *         this reset control belongs to
   * @id: ID of the reset controller in the reset
   *      controller device
   */
  struct reset_control {
  	struct reset_controller_dev *rcdev;
61fc41317   Philipp Zabel   reset: Add reset ...
33
34
35
36
37
38
39
40
41
42
43
44
  	unsigned int id;
  };
  
  /**
   * of_reset_simple_xlate - translate reset_spec to the reset line number
   * @rcdev: a pointer to the reset controller device
   * @reset_spec: reset line specifier as found in the device tree
   * @flags: a flags pointer to fill in (optional)
   *
   * This simple translation function should be used for reset controllers
   * with 1:1 mapping, where reset lines can be indexed by number without gaps.
   */
0c5b2b915   Rashika Kheria   reset: Mark funct...
45
  static int of_reset_simple_xlate(struct reset_controller_dev *rcdev,
61fc41317   Philipp Zabel   reset: Add reset ...
46
47
48
49
50
51
52
53
54
55
  			  const struct of_phandle_args *reset_spec)
  {
  	if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
  		return -EINVAL;
  
  	if (reset_spec->args[0] >= rcdev->nr_resets)
  		return -EINVAL;
  
  	return reset_spec->args[0];
  }
61fc41317   Philipp Zabel   reset: Add reset ...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  
  /**
   * reset_controller_register - register a reset controller device
   * @rcdev: a pointer to the initialized reset controller device
   */
  int reset_controller_register(struct reset_controller_dev *rcdev)
  {
  	if (!rcdev->of_xlate) {
  		rcdev->of_reset_n_cells = 1;
  		rcdev->of_xlate = of_reset_simple_xlate;
  	}
  
  	mutex_lock(&reset_controller_list_mutex);
  	list_add(&rcdev->list, &reset_controller_list);
  	mutex_unlock(&reset_controller_list_mutex);
  
  	return 0;
  }
  EXPORT_SYMBOL_GPL(reset_controller_register);
  
  /**
   * reset_controller_unregister - unregister a reset controller device
   * @rcdev: a pointer to the reset controller device
   */
  void reset_controller_unregister(struct reset_controller_dev *rcdev)
  {
  	mutex_lock(&reset_controller_list_mutex);
  	list_del(&rcdev->list);
  	mutex_unlock(&reset_controller_list_mutex);
  }
  EXPORT_SYMBOL_GPL(reset_controller_unregister);
  
  /**
   * reset_control_reset - reset the controlled device
   * @rstc: reset controller
   */
  int reset_control_reset(struct reset_control *rstc)
  {
  	if (rstc->rcdev->ops->reset)
  		return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id);
39b4da71c   Philipp Zabel   reset: use ENOTSU...
96
  	return -ENOTSUPP;
61fc41317   Philipp Zabel   reset: Add reset ...
97
98
99
100
101
102
103
104
105
106
107
  }
  EXPORT_SYMBOL_GPL(reset_control_reset);
  
  /**
   * reset_control_assert - asserts the reset line
   * @rstc: reset controller
   */
  int reset_control_assert(struct reset_control *rstc)
  {
  	if (rstc->rcdev->ops->assert)
  		return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id);
39b4da71c   Philipp Zabel   reset: use ENOTSU...
108
  	return -ENOTSUPP;
61fc41317   Philipp Zabel   reset: Add reset ...
109
110
111
112
113
114
115
116
117
118
119
  }
  EXPORT_SYMBOL_GPL(reset_control_assert);
  
  /**
   * reset_control_deassert - deasserts the reset line
   * @rstc: reset controller
   */
  int reset_control_deassert(struct reset_control *rstc)
  {
  	if (rstc->rcdev->ops->deassert)
  		return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id);
39b4da71c   Philipp Zabel   reset: use ENOTSU...
120
  	return -ENOTSUPP;
61fc41317   Philipp Zabel   reset: Add reset ...
121
122
123
124
  }
  EXPORT_SYMBOL_GPL(reset_control_deassert);
  
  /**
729de41ba   Dinh Nguyen   reset: add reset_...
125
126
127
128
129
130
131
132
133
   * reset_control_status - returns a negative errno if not supported, a
   * positive value if the reset line is asserted, or zero if the reset
   * line is not asserted.
   * @rstc: reset controller
   */
  int reset_control_status(struct reset_control *rstc)
  {
  	if (rstc->rcdev->ops->status)
  		return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
39b4da71c   Philipp Zabel   reset: use ENOTSU...
134
  	return -ENOTSUPP;
729de41ba   Dinh Nguyen   reset: add reset_...
135
136
137
138
  }
  EXPORT_SYMBOL_GPL(reset_control_status);
  
  /**
c0a13aa6d   Vince Hsu   reset: add of_res...
139
140
   * of_reset_control_get_by_index - Lookup and obtain a reference to a reset
   * controller by index.
fc0a59215   Maxime Ripard   reset: Add of_res...
141
   * @node: device to be reset by the controller
c0a13aa6d   Vince Hsu   reset: add of_res...
142
   * @index: index of the reset controller
61fc41317   Philipp Zabel   reset: Add reset ...
143
   *
c0a13aa6d   Vince Hsu   reset: add of_res...
144
145
146
   * This is to be used to perform a list of resets for a device or power domain
   * in whatever order. Returns a struct reset_control or IS_ERR() condition
   * containing errno.
61fc41317   Philipp Zabel   reset: Add reset ...
147
   */
c0a13aa6d   Vince Hsu   reset: add of_res...
148
149
  struct reset_control *of_reset_control_get_by_index(struct device_node *node,
  					   int index)
61fc41317   Philipp Zabel   reset: Add reset ...
150
151
152
153
  {
  	struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
  	struct reset_controller_dev *r, *rcdev;
  	struct of_phandle_args args;
61fc41317   Philipp Zabel   reset: Add reset ...
154
155
  	int rstc_id;
  	int ret;
fc0a59215   Maxime Ripard   reset: Add of_res...
156
  	ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
61fc41317   Philipp Zabel   reset: Add reset ...
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
  					 index, &args);
  	if (ret)
  		return ERR_PTR(ret);
  
  	mutex_lock(&reset_controller_list_mutex);
  	rcdev = NULL;
  	list_for_each_entry(r, &reset_controller_list, list) {
  		if (args.np == r->of_node) {
  			rcdev = r;
  			break;
  		}
  	}
  	of_node_put(args.np);
  
  	if (!rcdev) {
  		mutex_unlock(&reset_controller_list_mutex);
3d1030204   Philipp Zabel   reset: allow driv...
173
  		return ERR_PTR(-EPROBE_DEFER);
61fc41317   Philipp Zabel   reset: Add reset ...
174
175
176
177
178
179
180
181
182
183
184
185
186
  	}
  
  	rstc_id = rcdev->of_xlate(rcdev, &args);
  	if (rstc_id < 0) {
  		mutex_unlock(&reset_controller_list_mutex);
  		return ERR_PTR(rstc_id);
  	}
  
  	try_module_get(rcdev->owner);
  	mutex_unlock(&reset_controller_list_mutex);
  
  	rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
  	if (!rstc) {
6034bb22d   Dan Carpenter   reset: NULL deref...
187
  		module_put(rcdev->owner);
61fc41317   Philipp Zabel   reset: Add reset ...
188
189
  		return ERR_PTR(-ENOMEM);
  	}
61fc41317   Philipp Zabel   reset: Add reset ...
190
191
192
193
194
  	rstc->rcdev = rcdev;
  	rstc->id = rstc_id;
  
  	return rstc;
  }
c0a13aa6d   Vince Hsu   reset: add of_res...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  EXPORT_SYMBOL_GPL(of_reset_control_get_by_index);
  
  /**
   * of_reset_control_get - Lookup and obtain a reference to a reset controller.
   * @node: device to be reset by the controller
   * @id: reset line name
   *
   * Returns a struct reset_control or IS_ERR() condition containing errno.
   *
   * Use of id names is optional.
   */
  struct reset_control *of_reset_control_get(struct device_node *node,
  					   const char *id)
  {
  	int index = 0;
3d81216fd   Alban Bedel   reset: Fix of_res...
210
  	if (id) {
c0a13aa6d   Vince Hsu   reset: add of_res...
211
212
  		index = of_property_match_string(node,
  						 "reset-names", id);
3d81216fd   Alban Bedel   reset: Fix of_res...
213
214
215
  		if (index < 0)
  			return ERR_PTR(-ENOENT);
  	}
c0a13aa6d   Vince Hsu   reset: add of_res...
216
217
  	return of_reset_control_get_by_index(node, index);
  }
fc0a59215   Maxime Ripard   reset: Add of_res...
218
219
220
221
222
223
224
225
226
227
228
229
230
  EXPORT_SYMBOL_GPL(of_reset_control_get);
  
  /**
   * reset_control_get - Lookup and obtain a reference to a reset controller.
   * @dev: device to be reset by the controller
   * @id: reset line name
   *
   * Returns a struct reset_control or IS_ERR() condition containing errno.
   *
   * Use of id names is optional.
   */
  struct reset_control *reset_control_get(struct device *dev, const char *id)
  {
fc0a59215   Maxime Ripard   reset: Add of_res...
231
232
  	if (!dev)
  		return ERR_PTR(-EINVAL);
b354f68ff   Philipp Zabel   reset: remove unu...
233
  	return of_reset_control_get(dev->of_node, id);
fc0a59215   Maxime Ripard   reset: Add of_res...
234
  }
61fc41317   Philipp Zabel   reset: Add reset ...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  EXPORT_SYMBOL_GPL(reset_control_get);
  
  /**
   * reset_control_put - free the reset controller
   * @rstc: reset controller
   */
  
  void reset_control_put(struct reset_control *rstc)
  {
  	if (IS_ERR(rstc))
  		return;
  
  	module_put(rstc->rcdev->owner);
  	kfree(rstc);
  }
  EXPORT_SYMBOL_GPL(reset_control_put);
  
  static void devm_reset_control_release(struct device *dev, void *res)
  {
  	reset_control_put(*(struct reset_control **)res);
  }
  
  /**
   * devm_reset_control_get - resource managed reset_control_get()
   * @dev: device to be reset by the controller
   * @id: reset line name
   *
   * Managed reset_control_get(). For reset controllers returned from this
   * function, reset_control_put() is called automatically on driver detach.
   * See reset_control_get() for more information.
   */
  struct reset_control *devm_reset_control_get(struct device *dev, const char *id)
  {
  	struct reset_control **ptr, *rstc;
  
  	ptr = devres_alloc(devm_reset_control_release, sizeof(*ptr),
  			   GFP_KERNEL);
  	if (!ptr)
  		return ERR_PTR(-ENOMEM);
  
  	rstc = reset_control_get(dev, id);
  	if (!IS_ERR(rstc)) {
  		*ptr = rstc;
  		devres_add(dev, ptr);
  	} else {
  		devres_free(ptr);
  	}
  
  	return rstc;
  }
  EXPORT_SYMBOL_GPL(devm_reset_control_get);
61fc41317   Philipp Zabel   reset: Add reset ...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
  /**
   * device_reset - find reset controller associated with the device
   *                and perform reset
   * @dev: device to be reset by the controller
   *
   * Convenience wrapper for reset_control_get() and reset_control_reset().
   * This is useful for the common case of devices with single, dedicated reset
   * lines.
   */
  int device_reset(struct device *dev)
  {
  	struct reset_control *rstc;
  	int ret;
  
  	rstc = reset_control_get(dev, NULL);
  	if (IS_ERR(rstc))
  		return PTR_ERR(rstc);
  
  	ret = reset_control_reset(rstc);
  
  	reset_control_put(rstc);
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(device_reset);