Blame view

drivers/regulator/of_regulator.c 16.4 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
8f446e6fa   Rajendra Nayak   regulator: helper...
2
3
4
5
6
  /*
   * OF helpers for regulator framework
   *
   * Copyright (C) 2011 Texas Instruments, Inc.
   * Rajendra Nayak <rnayak@ti.com>
8f446e6fa   Rajendra Nayak   regulator: helper...
7
   */
e69af5e96   Axel Lin   regulator: export...
8
  #include <linux/module.h>
8f446e6fa   Rajendra Nayak   regulator: helper...
9
10
11
  #include <linux/slab.h>
  #include <linux/of.h>
  #include <linux/regulator/machine.h>
a0c7b164a   Mark Brown   regulator: of: Pr...
12
  #include <linux/regulator/driver.h>
1c8fa58f4   Thierry Reding   regulator: Add ge...
13
  #include <linux/regulator/of_regulator.h>
8f446e6fa   Rajendra Nayak   regulator: helper...
14

a0c7b164a   Mark Brown   regulator: of: Pr...
15
  #include "internal.h"
f32fa89ca   Krzysztof Kozlowski   regulator: Static...
16
  static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
f2b407698   Andrei.Stefanescu@microchip.com   regulator: of: ad...
17
  	[PM_SUSPEND_STANDBY]	= "regulator-state-standby",
40e20d68b   Chanwoo Choi   regulator: of: Ad...
18
19
20
  	[PM_SUSPEND_MEM]	= "regulator-state-mem",
  	[PM_SUSPEND_MAX]	= "regulator-state-disk",
  };
d8ca7d184   Dmitry Osipenko   regulator: core: ...
21
22
  static int of_get_regulation_constraints(struct device *dev,
  					struct device_node *np,
5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
23
24
  					struct regulator_init_data **init_data,
  					const struct regulator_desc *desc)
8f446e6fa   Rajendra Nayak   regulator: helper...
25
  {
8f446e6fa   Rajendra Nayak   regulator: helper...
26
  	struct regulation_constraints *constraints = &(*init_data)->constraints;
40e20d68b   Chanwoo Choi   regulator: of: Ad...
27
28
  	struct regulator_state *suspend_state;
  	struct device_node *suspend_np;
02f370393   Douglas Anderson   regulator: Don't ...
29
  	unsigned int mode;
54557ad97   David Collins   regulator: of: ad...
30
  	int ret, i, len;
d8ca7d184   Dmitry Osipenko   regulator: core: ...
31
  	int n_phandles;
00c877c69   Laxman Dewangan   regulator: core: ...
32
  	u32 pval;
8f446e6fa   Rajendra Nayak   regulator: helper...
33

d8ca7d184   Dmitry Osipenko   regulator: core: ...
34
35
36
  	n_phandles = of_count_phandle_with_args(np, "regulator-coupled-with",
  						NULL);
  	n_phandles = max(n_phandles, 0);
8f446e6fa   Rajendra Nayak   regulator: helper...
37
  	constraints->name = of_get_property(np, "regulator-name", NULL);
a34785f10   Laxman Dewangan   regulator: of: Us...
38
39
40
41
42
  	if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
  		constraints->min_uV = pval;
  
  	if (!of_property_read_u32(np, "regulator-max-microvolt", &pval))
  		constraints->max_uV = pval;
8f446e6fa   Rajendra Nayak   regulator: helper...
43
44
  
  	/* Voltage change possible? */
45fa2038c   Mark Brown   regulator: of: Do...
45
  	if (constraints->min_uV != constraints->max_uV)
8f446e6fa   Rajendra Nayak   regulator: helper...
46
  		constraints->valid_ops_mask |= REGULATOR_CHANGE_VOLTAGE;
45fa2038c   Mark Brown   regulator: of: Do...
47
48
49
  
  	/* Do we have a voltage range, if so try to apply it? */
  	if (constraints->min_uV && constraints->max_uV)
ab62aa931   Mark Brown   regulator: If a s...
50
  		constraints->apply_uV = true;
8f446e6fa   Rajendra Nayak   regulator: helper...
51

1e050eabb   Sergei Shtylyov   regulator: use of...
52
53
54
55
56
57
  	if (!of_property_read_u32(np, "regulator-microvolt-offset", &pval))
  		constraints->uV_offset = pval;
  	if (!of_property_read_u32(np, "regulator-min-microamp", &pval))
  		constraints->min_uA = pval;
  	if (!of_property_read_u32(np, "regulator-max-microamp", &pval))
  		constraints->max_uA = pval;
8f446e6fa   Rajendra Nayak   regulator: helper...
58

36e4f839d   Stephen Boyd   regulator: Add in...
59
60
61
  	if (!of_property_read_u32(np, "regulator-input-current-limit-microamp",
  				  &pval))
  		constraints->ilim_uA = pval;
8f446e6fa   Rajendra Nayak   regulator: helper...
62
63
64
  	/* Current change possible? */
  	if (constraints->min_uA != constraints->max_uA)
  		constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
1e050eabb   Sergei Shtylyov   regulator: use of...
65
66
67
  	constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
  	constraints->always_on = of_property_read_bool(np, "regulator-always-on");
  	if (!constraints->always_on) /* status change should be possible. */
8f446e6fa   Rajendra Nayak   regulator: helper...
68
  		constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
6f0b2c696   Yadwinder Singh Brar   regulator: Add ra...
69

23c779b9f   Stephen Boyd   regulator: Add pu...
70
  	constraints->pull_down = of_property_read_bool(np, "regulator-pull-down");
93134c7b4   Kishon Vijay Abraham I   regulator: of: Ad...
71
72
  	if (of_property_read_bool(np, "regulator-allow-bypass"))
  		constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
b263d2037   Bjorn Andersson   regulator: Introd...
73
74
  	if (of_property_read_bool(np, "regulator-allow-set-load"))
  		constraints->valid_ops_mask |= REGULATOR_CHANGE_DRMS;
1e050eabb   Sergei Shtylyov   regulator: use of...
75
76
77
78
  	ret = of_property_read_u32(np, "regulator-ramp-delay", &pval);
  	if (!ret) {
  		if (pval)
  			constraints->ramp_delay = pval;
1653ccf4c   Yadwinder Singh Brar   regulator: core: ...
79
80
81
  		else
  			constraints->ramp_disable = true;
  	}
00c877c69   Laxman Dewangan   regulator: core: ...
82

d6c1dc3f5   Laxman Dewangan   regulator: Add se...
83
84
85
  	ret = of_property_read_u32(np, "regulator-settling-time-us", &pval);
  	if (!ret)
  		constraints->settling_time = pval;
3ffad468c   Matthias Kaehlcke   regulator: Allow ...
86
87
88
89
  	ret = of_property_read_u32(np, "regulator-settling-time-up-us", &pval);
  	if (!ret)
  		constraints->settling_time_up = pval;
  	if (constraints->settling_time_up && constraints->settling_time) {
0c9721a5d   Rob Herring   regulator: Conver...
90
91
92
  		pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-up-us'
  ",
  			np);
3ffad468c   Matthias Kaehlcke   regulator: Allow ...
93
94
95
96
97
98
99
100
  		constraints->settling_time_up = 0;
  	}
  
  	ret = of_property_read_u32(np, "regulator-settling-time-down-us",
  				   &pval);
  	if (!ret)
  		constraints->settling_time_down = pval;
  	if (constraints->settling_time_down && constraints->settling_time) {
0c9721a5d   Rob Herring   regulator: Conver...
101
102
103
  		pr_warn("%pOFn: ambiguous configuration for settling time, ignoring 'regulator-settling-time-down-us'
  ",
  			np);
3ffad468c   Matthias Kaehlcke   regulator: Allow ...
104
105
  		constraints->settling_time_down = 0;
  	}
00c877c69   Laxman Dewangan   regulator: core: ...
106
107
108
  	ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
  	if (!ret)
  		constraints->enable_time = pval;
40e20d68b   Chanwoo Choi   regulator: of: Ad...
109

57f66b788   Stephen Boyd   regulator: Add so...
110
111
  	constraints->soft_start = of_property_read_bool(np,
  					"regulator-soft-start");
670666b9e   Laxman Dewangan   regulator: core: ...
112
113
114
115
116
117
  	ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
  	if (!ret) {
  		constraints->active_discharge =
  				(pval) ? REGULATOR_ACTIVE_DISCHARGE_ENABLE :
  					REGULATOR_ACTIVE_DISCHARGE_DISABLE;
  	}
57f66b788   Stephen Boyd   regulator: Add so...
118

5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
119
120
  	if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
  		if (desc && desc->of_map_mode) {
02f370393   Douglas Anderson   regulator: Don't ...
121
122
  			mode = desc->of_map_mode(pval);
  			if (mode == REGULATOR_MODE_INVALID)
0c9721a5d   Rob Herring   regulator: Conver...
123
124
  				pr_err("%pOFn: invalid mode %u
  ", np, pval);
5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
125
  			else
02f370393   Douglas Anderson   regulator: Don't ...
126
  				constraints->initial_mode = mode;
5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
127
  		} else {
0c9721a5d   Rob Herring   regulator: Conver...
128
129
130
  			pr_warn("%pOFn: mapping for mode %d not defined
  ",
  				np, pval);
5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
131
132
  		}
  	}
54557ad97   David Collins   regulator: of: ad...
133
134
135
136
137
138
139
140
  	len = of_property_count_elems_of_size(np, "regulator-allowed-modes",
  						sizeof(u32));
  	if (len > 0) {
  		if (desc && desc->of_map_mode) {
  			for (i = 0; i < len; i++) {
  				ret = of_property_read_u32_index(np,
  					"regulator-allowed-modes", i, &pval);
  				if (ret) {
0c9721a5d   Rob Herring   regulator: Conver...
141
142
143
  					pr_err("%pOFn: couldn't read allowed modes index %d, ret=%d
  ",
  						np, i, ret);
54557ad97   David Collins   regulator: of: ad...
144
145
146
147
  					break;
  				}
  				mode = desc->of_map_mode(pval);
  				if (mode == REGULATOR_MODE_INVALID)
0c9721a5d   Rob Herring   regulator: Conver...
148
149
150
  					pr_err("%pOFn: invalid regulator-allowed-modes element %u
  ",
  						np, pval);
54557ad97   David Collins   regulator: of: ad...
151
152
153
154
155
156
157
  				else
  					constraints->valid_modes_mask |= mode;
  			}
  			if (constraints->valid_modes_mask)
  				constraints->valid_ops_mask
  					|= REGULATOR_CHANGE_MODE;
  		} else {
0c9721a5d   Rob Herring   regulator: Conver...
158
159
  			pr_warn("%pOFn: mode mapping not defined
  ", np);
54557ad97   David Collins   regulator: of: ad...
160
161
  		}
  	}
22a10bca2   Stephen Boyd   regulator: Add sy...
162
163
  	if (!of_property_read_u32(np, "regulator-system-load", &pval))
  		constraints->system_load = pval;
d8ca7d184   Dmitry Osipenko   regulator: core: ...
164
165
166
167
168
169
170
171
172
173
174
  	if (n_phandles) {
  		constraints->max_spread = devm_kzalloc(dev,
  				sizeof(*constraints->max_spread) * n_phandles,
  				GFP_KERNEL);
  
  		if (!constraints->max_spread)
  			return -ENOMEM;
  
  		of_property_read_u32_array(np, "regulator-coupled-max-spread",
  					   constraints->max_spread, n_phandles);
  	}
a085a31af   Maciej Purski   regulator: core: ...
175

85254bcf3   Dmitry Osipenko   regulator: core: ...
176
177
178
  	if (!of_property_read_u32(np, "regulator-max-step-microvolt",
  				  &pval))
  		constraints->max_uV_step = pval;
3a003baee   Stephen Boyd   regulator: Add ov...
179
180
  	constraints->over_current_protection = of_property_read_bool(np,
  					"regulator-over-current-protection");
40e20d68b   Chanwoo Choi   regulator: of: Ad...
181
182
183
184
185
186
187
188
  	for (i = 0; i < ARRAY_SIZE(regulator_states); i++) {
  		switch (i) {
  		case PM_SUSPEND_MEM:
  			suspend_state = &constraints->state_mem;
  			break;
  		case PM_SUSPEND_MAX:
  			suspend_state = &constraints->state_disk;
  			break;
f2b407698   Andrei.Stefanescu@microchip.com   regulator: of: ad...
189
190
191
  		case PM_SUSPEND_STANDBY:
  			suspend_state = &constraints->state_standby;
  			break;
40e20d68b   Chanwoo Choi   regulator: of: Ad...
192
  		case PM_SUSPEND_ON:
690cbb90a   Rafael J. Wysocki   PM / s2idle: Rena...
193
  		case PM_SUSPEND_TO_IDLE:
40e20d68b   Chanwoo Choi   regulator: of: Ad...
194
195
  		default:
  			continue;
7cf225b98   Krzysztof Kozlowski   regulator: Remove...
196
  		}
40e20d68b   Chanwoo Choi   regulator: of: Ad...
197
198
199
200
  
  		suspend_np = of_get_child_by_name(np, regulator_states[i]);
  		if (!suspend_np || !suspend_state)
  			continue;
5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
201
202
203
  		if (!of_property_read_u32(suspend_np, "regulator-mode",
  					  &pval)) {
  			if (desc && desc->of_map_mode) {
02f370393   Douglas Anderson   regulator: Don't ...
204
205
  				mode = desc->of_map_mode(pval);
  				if (mode == REGULATOR_MODE_INVALID)
0c9721a5d   Rob Herring   regulator: Conver...
206
207
208
  					pr_err("%pOFn: invalid mode %u
  ",
  					       np, pval);
5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
209
  				else
02f370393   Douglas Anderson   regulator: Don't ...
210
  					suspend_state->mode = mode;
5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
211
  			} else {
0c9721a5d   Rob Herring   regulator: Conver...
212
213
214
  				pr_warn("%pOFn: mapping for mode %d not defined
  ",
  					np, pval);
5e5e3a42c   Javier Martinez Canillas   regulator: of: Ad...
215
216
  			}
  		}
40e20d68b   Chanwoo Choi   regulator: of: Ad...
217
218
  		if (of_property_read_bool(suspend_np,
  					"regulator-on-in-suspend"))
72069f995   Chunyan Zhang   regulator: leave ...
219
  			suspend_state->enabled = ENABLE_IN_SUSPEND;
40e20d68b   Chanwoo Choi   regulator: of: Ad...
220
221
  		else if (of_property_read_bool(suspend_np,
  					"regulator-off-in-suspend"))
72069f995   Chunyan Zhang   regulator: leave ...
222
  			suspend_state->enabled = DISABLE_IN_SUSPEND;
40e20d68b   Chanwoo Choi   regulator: of: Ad...
223

131cb1210   Marco Felsch   regulator: of: fi...
224
225
  		if (!of_property_read_u32(suspend_np,
  				"regulator-suspend-min-microvolt", &pval))
f7efad10b   Chunyan Zhang   regulator: add PM...
226
  			suspend_state->min_uV = pval;
131cb1210   Marco Felsch   regulator: of: fi...
227
228
  		if (!of_property_read_u32(suspend_np,
  				"regulator-suspend-max-microvolt", &pval))
f7efad10b   Chunyan Zhang   regulator: add PM...
229
  			suspend_state->max_uV = pval;
40e20d68b   Chanwoo Choi   regulator: of: Ad...
230

8cbcaea89   Doug Anderson   regulator: of: Ad...
231
232
233
  		if (!of_property_read_u32(suspend_np,
  					"regulator-suspend-microvolt", &pval))
  			suspend_state->uV = pval;
f7efad10b   Chunyan Zhang   regulator: add PM...
234
235
236
237
238
239
  		else /* otherwise use min_uV as default suspend voltage */
  			suspend_state->uV = suspend_state->min_uV;
  
  		if (of_property_read_bool(suspend_np,
  					"regulator-changeable-in-suspend"))
  			suspend_state->changeable = true;
8cbcaea89   Doug Anderson   regulator: of: Ad...
240

a0f78bc89   Keerthy   regulator: of: se...
241
242
  		if (i == PM_SUSPEND_MEM)
  			constraints->initial_state = PM_SUSPEND_MEM;
4eafec83a   Javier Martinez Canillas   regulator: of: De...
243
  		of_node_put(suspend_np);
40e20d68b   Chanwoo Choi   regulator: of: Ad...
244
245
246
  		suspend_state = NULL;
  		suspend_np = NULL;
  	}
d8ca7d184   Dmitry Osipenko   regulator: core: ...
247
248
  
  	return 0;
8f446e6fa   Rajendra Nayak   regulator: helper...
249
250
251
252
253
  }
  
  /**
   * of_get_regulator_init_data - extract regulator_init_data structure info
   * @dev: device requesting for regulator_init_data
072e78b12   Javier Martinez Canillas   regulator: of: Ad...
254
255
   * @node: regulator device node
   * @desc: regulator description
8f446e6fa   Rajendra Nayak   regulator: helper...
256
257
   *
   * Populates regulator_init_data structure by extracting data from device
48f1b4efd   Krzysztof Kozlowski   regulator: Fix tr...
258
   * tree node, returns a pointer to the populated structure or NULL if memory
8f446e6fa   Rajendra Nayak   regulator: helper...
259
260
   * alloc fails.
   */
d9a861cce   Shawn Guo   regulator: pass d...
261
  struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
072e78b12   Javier Martinez Canillas   regulator: of: Ad...
262
263
  					  struct device_node *node,
  					  const struct regulator_desc *desc)
8f446e6fa   Rajendra Nayak   regulator: helper...
264
265
  {
  	struct regulator_init_data *init_data;
d9a861cce   Shawn Guo   regulator: pass d...
266
  	if (!node)
8f446e6fa   Rajendra Nayak   regulator: helper...
267
268
269
270
271
  		return NULL;
  
  	init_data = devm_kzalloc(dev, sizeof(*init_data), GFP_KERNEL);
  	if (!init_data)
  		return NULL; /* Out of memory? */
d8ca7d184   Dmitry Osipenko   regulator: core: ...
272
273
  	if (of_get_regulation_constraints(dev, node, &init_data, desc))
  		return NULL;
8f446e6fa   Rajendra Nayak   regulator: helper...
274
275
  	return init_data;
  }
e69af5e96   Axel Lin   regulator: export...
276
  EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
1c8fa58f4   Thierry Reding   regulator: Add ge...
277

13b3fde80   Charles Keepax   regulator: core: ...
278
279
280
281
282
283
284
285
286
287
288
289
290
  struct devm_of_regulator_matches {
  	struct of_regulator_match *matches;
  	unsigned int num_matches;
  };
  
  static void devm_of_regulator_put_matches(struct device *dev, void *res)
  {
  	struct devm_of_regulator_matches *devm_matches = res;
  	int i;
  
  	for (i = 0; i < devm_matches->num_matches; i++)
  		of_node_put(devm_matches->matches[i].of_node);
  }
1c8fa58f4   Thierry Reding   regulator: Add ge...
291
  /**
13511def8   Stephen Warren   regulator: deprec...
292
   * of_regulator_match - extract multiple regulator init data from device tree.
1c8fa58f4   Thierry Reding   regulator: Add ge...
293
294
295
296
297
   * @dev: device requesting the data
   * @node: parent device node of the regulators
   * @matches: match table for the regulators
   * @num_matches: number of entries in match table
   *
13511def8   Stephen Warren   regulator: deprec...
298
299
300
301
302
303
   * This function uses a match table specified by the regulator driver to
   * parse regulator init data from the device tree. @node is expected to
   * contain a set of child nodes, each providing the init data for one
   * regulator. The data parsed from a child node will be matched to a regulator
   * based on either the deprecated property regulator-compatible if present,
   * or otherwise the child node's name. Note that the match table is modified
bd0dda744   Charles Keepax   regulator: core: ...
304
305
   * in place and an additional of_node reference is taken for each matched
   * regulator.
1c8fa58f4   Thierry Reding   regulator: Add ge...
306
307
308
309
310
311
312
313
314
   *
   * Returns the number of matches found or a negative error code on failure.
   */
  int of_regulator_match(struct device *dev, struct device_node *node,
  		       struct of_regulator_match *matches,
  		       unsigned int num_matches)
  {
  	unsigned int count = 0;
  	unsigned int i;
13511def8   Stephen Warren   regulator: deprec...
315
  	const char *name;
5260cd2bc   Laxman Dewangan   regulator: dt: re...
316
  	struct device_node *child;
13b3fde80   Charles Keepax   regulator: core: ...
317
  	struct devm_of_regulator_matches *devm_matches;
1c8fa58f4   Thierry Reding   regulator: Add ge...
318
319
320
  
  	if (!dev || !node)
  		return -EINVAL;
13b3fde80   Charles Keepax   regulator: core: ...
321
322
323
324
325
326
327
328
329
330
  	devm_matches = devres_alloc(devm_of_regulator_put_matches,
  				    sizeof(struct devm_of_regulator_matches),
  				    GFP_KERNEL);
  	if (!devm_matches)
  		return -ENOMEM;
  
  	devm_matches->matches = matches;
  	devm_matches->num_matches = num_matches;
  
  	devres_add(dev, devm_matches);
a2f95c363   Stephen Warren   regulator: clear ...
331
332
333
334
335
  	for (i = 0; i < num_matches; i++) {
  		struct of_regulator_match *match = &matches[i];
  		match->init_data = NULL;
  		match->of_node = NULL;
  	}
5260cd2bc   Laxman Dewangan   regulator: dt: re...
336
  	for_each_child_of_node(node, child) {
13511def8   Stephen Warren   regulator: deprec...
337
  		name = of_get_property(child,
5260cd2bc   Laxman Dewangan   regulator: dt: re...
338
  					"regulator-compatible", NULL);
13511def8   Stephen Warren   regulator: deprec...
339
340
  		if (!name)
  			name = child->name;
5260cd2bc   Laxman Dewangan   regulator: dt: re...
341
342
343
344
  		for (i = 0; i < num_matches; i++) {
  			struct of_regulator_match *match = &matches[i];
  			if (match->of_node)
  				continue;
13511def8   Stephen Warren   regulator: deprec...
345
  			if (strcmp(match->name, name))
5260cd2bc   Laxman Dewangan   regulator: dt: re...
346
347
348
  				continue;
  
  			match->init_data =
75d6b2faf   Javier Martinez Canillas   regulator: of: Pa...
349
350
  				of_get_regulator_init_data(dev, child,
  							   match->desc);
5260cd2bc   Laxman Dewangan   regulator: dt: re...
351
352
  			if (!match->init_data) {
  				dev_err(dev,
0c9721a5d   Rob Herring   regulator: Conver...
353
354
355
  					"failed to parse DT for regulator %pOFn
  ",
  					child);
30966861a   Christophe JAILLET   regulator: of: Ad...
356
  				of_node_put(child);
5260cd2bc   Laxman Dewangan   regulator: dt: re...
357
358
  				return -EINVAL;
  			}
bd0dda744   Charles Keepax   regulator: core: ...
359
  			match->of_node = of_node_get(child);
5260cd2bc   Laxman Dewangan   regulator: dt: re...
360
361
  			count++;
  			break;
1c8fa58f4   Thierry Reding   regulator: Add ge...
362
  		}
1c8fa58f4   Thierry Reding   regulator: Add ge...
363
364
365
366
367
  	}
  
  	return count;
  }
  EXPORT_SYMBOL_GPL(of_regulator_match);
a0c7b164a   Mark Brown   regulator: of: Pr...
368

7a67eb1d3   YueHaibing   regulator: of: Ma...
369
370
371
  static struct
  device_node *regulator_of_get_init_node(struct device *dev,
  					const struct regulator_desc *desc)
a0c7b164a   Mark Brown   regulator: of: Pr...
372
373
  {
  	struct device_node *search, *child;
a0c7b164a   Mark Brown   regulator: of: Pr...
374
375
376
377
  	const char *name;
  
  	if (!dev->of_node || !desc->of_match)
  		return NULL;
eba9473f6   Charles Keepax   regulator: Allow ...
378
  	if (desc->regulators_node) {
a0c7b164a   Mark Brown   regulator: of: Pr...
379
380
  		search = of_get_child_by_name(dev->of_node,
  					      desc->regulators_node);
eba9473f6   Charles Keepax   regulator: Allow ...
381
  	} else {
423a11647   Frank Rowand   regulator: of: re...
382
  		search = of_node_get(dev->of_node);
a0c7b164a   Mark Brown   regulator: of: Pr...
383

eba9473f6   Charles Keepax   regulator: Allow ...
384
385
386
  		if (!strcmp(desc->of_match, search->name))
  			return search;
  	}
a0c7b164a   Mark Brown   regulator: of: Pr...
387
  	if (!search) {
7de79a1d4   Mark Brown   regulator: of: Lo...
388
389
390
  		dev_dbg(dev, "Failed to find regulator container node '%s'
  ",
  			desc->regulators_node);
a0c7b164a   Mark Brown   regulator: of: Pr...
391
392
  		return NULL;
  	}
130daa3f3   Stephen Boyd   regulator: of: Sk...
393
  	for_each_available_child_of_node(search, child) {
a0c7b164a   Mark Brown   regulator: of: Pr...
394
395
396
  		name = of_get_property(child, "regulator-compatible", NULL);
  		if (!name)
  			name = child->name;
811ba489f   Nishka Dasgupta   regulator: of: Ad...
397
398
  		if (!strcmp(desc->of_match, name)) {
  			of_node_put(search);
925c85e21   Charles Keepax   regulator: Factor...
399
  			return of_node_get(child);
811ba489f   Nishka Dasgupta   regulator: of: Ad...
400
  		}
925c85e21   Charles Keepax   regulator: Factor...
401
  	}
a0c7b164a   Mark Brown   regulator: of: Pr...
402

925c85e21   Charles Keepax   regulator: Factor...
403
  	of_node_put(search);
a0c7b164a   Mark Brown   regulator: of: Pr...
404

925c85e21   Charles Keepax   regulator: Factor...
405
406
  	return NULL;
  }
bfa21a0df   Krzysztof Kozlowski   regulator: Allow ...
407

925c85e21   Charles Keepax   regulator: Factor...
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
  struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
  					    const struct regulator_desc *desc,
  					    struct regulator_config *config,
  					    struct device_node **node)
  {
  	struct device_node *child;
  	struct regulator_init_data *init_data = NULL;
  
  	child = regulator_of_get_init_node(dev, desc);
  	if (!child)
  		return NULL;
  
  	init_data = of_get_regulator_init_data(dev, child, desc);
  	if (!init_data) {
  		dev_err(dev, "failed to parse DT for regulator %pOFn
  ", child);
  		goto error;
a0c7b164a   Mark Brown   regulator: of: Pr...
425
  	}
f8970d341   Marco Felsch   regulator: core: ...
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  	if (desc->of_parse_cb) {
  		int ret;
  
  		ret = desc->of_parse_cb(child, desc, config);
  		if (ret) {
  			if (ret == -EPROBE_DEFER) {
  				of_node_put(child);
  				return ERR_PTR(-EPROBE_DEFER);
  			}
  			dev_err(dev,
  				"driver callback failed to parse DT for regulator %pOFn
  ",
  				child);
  			goto error;
  		}
925c85e21   Charles Keepax   regulator: Factor...
441
442
443
  	}
  
  	*node = child;
a0c7b164a   Mark Brown   regulator: of: Pr...
444
445
  
  	return init_data;
925c85e21   Charles Keepax   regulator: Factor...
446
447
448
449
450
  
  error:
  	of_node_put(child);
  
  	return NULL;
a0c7b164a   Mark Brown   regulator: of: Pr...
451
  }
148096af0   Maciej Purski   regulator: core: ...
452

148096af0   Maciej Purski   regulator: core: ...
453
454
455
  struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
  {
  	struct device *dev;
cfba5de9b   Suzuki K Poulose   drivers: Introduc...
456
  	dev = class_find_device_by_of_node(&regulator_class, np);
148096af0   Maciej Purski   regulator: core: ...
457
458
459
  
  	return dev ? dev_to_rdev(dev) : NULL;
  }
a085a31af   Maciej Purski   regulator: core: ...
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  
  /*
   * Returns number of regulators coupled with rdev.
   */
  int of_get_n_coupled(struct regulator_dev *rdev)
  {
  	struct device_node *node = rdev->dev.of_node;
  	int n_phandles;
  
  	n_phandles = of_count_phandle_with_args(node,
  						"regulator-coupled-with",
  						NULL);
  
  	return (n_phandles > 0) ? n_phandles : 0;
  }
  
  /* Looks for "to_find" device_node in src's "regulator-coupled-with" property */
  static bool of_coupling_find_node(struct device_node *src,
d8ca7d184   Dmitry Osipenko   regulator: core: ...
478
479
  				  struct device_node *to_find,
  				  int *index)
a085a31af   Maciej Purski   regulator: core: ...
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  {
  	int n_phandles, i;
  	bool found = false;
  
  	n_phandles = of_count_phandle_with_args(src,
  						"regulator-coupled-with",
  						NULL);
  
  	for (i = 0; i < n_phandles; i++) {
  		struct device_node *tmp = of_parse_phandle(src,
  					   "regulator-coupled-with", i);
  
  		if (!tmp)
  			break;
  
  		/* found */
  		if (tmp == to_find)
  			found = true;
  
  		of_node_put(tmp);
d8ca7d184   Dmitry Osipenko   regulator: core: ...
500
501
  		if (found) {
  			*index = i;
a085a31af   Maciej Purski   regulator: core: ...
502
  			break;
d8ca7d184   Dmitry Osipenko   regulator: core: ...
503
  		}
a085a31af   Maciej Purski   regulator: core: ...
504
505
506
507
508
509
510
511
  	}
  
  	return found;
  }
  
  /**
   * of_check_coupling_data - Parse rdev's coupling properties and check data
   *			    consistency
45e8446e7   Lee Jones   regulator: of_reg...
512
   * @rdev: pointer to regulator_dev whose data is checked
a085a31af   Maciej Purski   regulator: core: ...
513
514
515
516
517
518
519
520
521
522
523
   *
   * Function checks if all the following conditions are met:
   * - rdev's max_spread is greater than 0
   * - all coupled regulators have the same max_spread
   * - all coupled regulators have the same number of regulator_dev phandles
   * - all regulators are linked to each other
   *
   * Returns true if all conditions are met.
   */
  bool of_check_coupling_data(struct regulator_dev *rdev)
  {
a085a31af   Maciej Purski   regulator: core: ...
524
525
526
  	struct device_node *node = rdev->dev.of_node;
  	int n_phandles = of_get_n_coupled(rdev);
  	struct device_node *c_node;
d8ca7d184   Dmitry Osipenko   regulator: core: ...
527
  	int index;
a085a31af   Maciej Purski   regulator: core: ...
528
529
  	int i;
  	bool ret = true;
a085a31af   Maciej Purski   regulator: core: ...
530
531
  	/* iterate over rdev's phandles */
  	for (i = 0; i < n_phandles; i++) {
d8ca7d184   Dmitry Osipenko   regulator: core: ...
532
  		int max_spread = rdev->constraints->max_spread[i];
a085a31af   Maciej Purski   regulator: core: ...
533
  		int c_max_spread, c_n_phandles;
d8ca7d184   Dmitry Osipenko   regulator: core: ...
534
535
536
537
538
  		if (max_spread <= 0) {
  			dev_err(&rdev->dev, "max_spread value invalid
  ");
  			return false;
  		}
a085a31af   Maciej Purski   regulator: core: ...
539
540
541
542
543
544
545
546
547
548
549
  		c_node = of_parse_phandle(node,
  					  "regulator-coupled-with", i);
  
  		if (!c_node)
  			ret = false;
  
  		c_n_phandles = of_count_phandle_with_args(c_node,
  							  "regulator-coupled-with",
  							  NULL);
  
  		if (c_n_phandles != n_phandles) {
48f1b4efd   Krzysztof Kozlowski   regulator: Fix tr...
550
551
  			dev_err(&rdev->dev, "number of coupled reg phandles mismatch
  ");
a085a31af   Maciej Purski   regulator: core: ...
552
553
554
  			ret = false;
  			goto clean;
  		}
d8ca7d184   Dmitry Osipenko   regulator: core: ...
555
556
557
  		if (!of_coupling_find_node(c_node, node, &index)) {
  			dev_err(&rdev->dev, "missing 2-way linking for coupled regulators
  ");
a085a31af   Maciej Purski   regulator: core: ...
558
559
560
  			ret = false;
  			goto clean;
  		}
d8ca7d184   Dmitry Osipenko   regulator: core: ...
561
562
  		if (of_property_read_u32_index(c_node, "regulator-coupled-max-spread",
  					       index, &c_max_spread)) {
a085a31af   Maciej Purski   regulator: core: ...
563
564
565
  			ret = false;
  			goto clean;
  		}
d8ca7d184   Dmitry Osipenko   regulator: core: ...
566
567
568
569
  		if (c_max_spread != max_spread) {
  			dev_err(&rdev->dev,
  				"coupled regulators max_spread mismatch
  ");
a085a31af   Maciej Purski   regulator: core: ...
570
  			ret = false;
d8ca7d184   Dmitry Osipenko   regulator: core: ...
571
  			goto clean;
a085a31af   Maciej Purski   regulator: core: ...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
  		}
  
  clean:
  		of_node_put(c_node);
  		if (!ret)
  			break;
  	}
  
  	return ret;
  }
  
  /**
   * of_parse_coupled regulator - Get regulator_dev pointer from rdev's property
   * @rdev: Pointer to regulator_dev, whose DTS is used as a source to parse
   *	  "regulator-coupled-with" property
   * @index: Index in phandles array
   *
   * Returns the regulator_dev pointer parsed from DTS. If it has not been yet
   * registered, returns NULL
   */
  struct regulator_dev *of_parse_coupled_regulator(struct regulator_dev *rdev,
  						 int index)
  {
  	struct device_node *node = rdev->dev.of_node;
  	struct device_node *c_node;
  	struct regulator_dev *c_rdev;
  
  	c_node = of_parse_phandle(node, "regulator-coupled-with", index);
  	if (!c_node)
  		return NULL;
  
  	c_rdev = of_find_regulator_by_node(c_node);
  
  	of_node_put(c_node);
  
  	return c_rdev;
  }