Blame view

drivers/of/platform.c 20 KB
af6074fc9   Rob Herring   of: Use SPDX lice...
1
  // SPDX-License-Identifier: GPL-2.0+
3f23de10f   Stephen Rothwell   Create drivers/of...
2
3
4
5
6
7
  /*
   *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
   *			 <benh@kernel.crashing.org>
   *    and		 Arnd Bergmann, IBM Corp.
   *    Merged from powerpc/kernel/of_platform.c and
   *    sparc{,64}/kernel/of_device.c by Stephen Rothwell
3f23de10f   Stephen Rothwell   Create drivers/of...
8
   */
606ad42aa   Rob Herring   of: use pr_fmt pr...
9
10
  
  #define pr_fmt(fmt)	"OF: " fmt
3f23de10f   Stephen Rothwell   Create drivers/of...
11
  #include <linux/errno.h>
5c4570835   Stephen Rothwell   [SPARC/64]: Conso...
12
  #include <linux/module.h>
5de1540b7   Grant Likely   drivers/amba: cre...
13
  #include <linux/amba/bus.h>
3f23de10f   Stephen Rothwell   Create drivers/of...
14
  #include <linux/device.h>
5fd200f3b   Grant Likely   of/device: Merge ...
15
  #include <linux/dma-mapping.h>
50ef5284e   Grant Likely   of: Fix missing i...
16
  #include <linux/slab.h>
9e3288dc9   Grant Likely   of/device: Fix bu...
17
  #include <linux/of_address.h>
3f23de10f   Stephen Rothwell   Create drivers/of...
18
  #include <linux/of_device.h>
09515ef5d   Sricharan R   of/acpi: Configur...
19
  #include <linux/of_iommu.h>
9e3288dc9   Grant Likely   of/device: Fix bu...
20
  #include <linux/of_irq.h>
3f23de10f   Stephen Rothwell   Create drivers/of...
21
  #include <linux/of_platform.h>
eca393016   Grant Likely   of: Merge of_plat...
22
  #include <linux/platform_device.h>
cbb49c266   Grant Likely   dt: Add default m...
23
24
  const struct of_device_id of_default_bus_match_table[] = {
  	{ .compatible = "simple-bus", },
22869a9ec   Linus Walleij   MFD/OF: document ...
25
  	{ .compatible = "simple-mfd", },
ecd76eded   Paul Burton   of/platform: Prob...
26
  	{ .compatible = "isa", },
cbb49c266   Grant Likely   dt: Add default m...
27
28
29
30
31
  #ifdef CONFIG_ARM_AMBA
  	{ .compatible = "arm,amba-bus", },
  #endif /* CONFIG_ARM_AMBA */
  	{} /* Empty terminated list */
  };
4550fe637   Viresh Kumar   of: Don't create ...
32
33
34
35
  static const struct of_device_id of_skipped_node_table[] = {
  	{ .compatible = "operating-points-v2", },
  	{} /* Empty terminated list */
  };
c60855840   Jonas Bonn   of: make of_find_...
36
37
38
39
  /**
   * of_find_device_by_node - Find the platform_device associated with a node
   * @np: Pointer to device tree node
   *
4fb373dfa   Johan Hovold   of/platform: clar...
40
41
42
   * Takes a reference to the embedded struct device which needs to be dropped
   * after use.
   *
c60855840   Jonas Bonn   of: make of_find_...
43
44
45
46
47
   * Returns platform_device pointer, or NULL if not found
   */
  struct platform_device *of_find_device_by_node(struct device_node *np)
  {
  	struct device *dev;
cfba5de9b   Suzuki K Poulose   drivers: Introduc...
48
  	dev = bus_find_device_by_of_node(&platform_bus_type, np);
c60855840   Jonas Bonn   of: make of_find_...
49
50
51
  	return dev ? to_platform_device(dev) : NULL;
  }
  EXPORT_SYMBOL(of_find_device_by_node);
964dba283   Grant Likely   devicetree: Add e...
52
  #ifdef CONFIG_OF_ADDRESS
5fd200f3b   Grant Likely   of/device: Merge ...
53
54
55
56
57
58
59
60
61
  /*
   * The following routines scan a subtree and registers a device for
   * each applicable node.
   *
   * Note: sparc doesn't use these routines because it has a different
   * mechanism for creating devices from device tree nodes.
   */
  
  /**
94c093198   Grant Likely   of: Merge of_devi...
62
63
64
   * of_device_make_bus_id - Use the device node data to assign a unique name
   * @dev: pointer to device structure that is linked to a device tree node
   *
07e461cd7   Grant Likely   of: Ensure unique...
65
66
67
   * This routine will first try using the translated bus address to
   * derive a unique name. If it cannot, then it will prepend names from
   * parent nodes until a unique name can be derived.
94c093198   Grant Likely   of: Merge of_devi...
68
   */
e553f539f   Frank Rowand   of: make of_devic...
69
  static void of_device_make_bus_id(struct device *dev)
94c093198   Grant Likely   of: Merge of_devi...
70
  {
94c093198   Grant Likely   of: Merge of_devi...
71
  	struct device_node *node = dev->of_node;
24fb530f9   Kim Phillips   of/platform: spar...
72
  	const __be32 *reg;
94c093198   Grant Likely   of: Merge of_devi...
73
  	u64 addr;
94c093198   Grant Likely   of: Merge of_devi...
74

07e461cd7   Grant Likely   of: Ensure unique...
75
76
77
78
79
80
81
82
  	/* Construct the name, using parent nodes if necessary to ensure uniqueness */
  	while (node->parent) {
  		/*
  		 * If the address can be translated, then that is as much
  		 * uniqueness as we need. Make it the first component and return
  		 */
  		reg = of_get_property(node, "reg", NULL);
  		if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
a613b26a5   Rob Herring   of: Convert to us...
83
  			dev_set_name(dev, dev_name(dev) ? "%llx.%pOFn:%s" : "%llx.%pOFn",
d88590dc2   Geert Uytterhoeven   of/platform: Drop...
84
  				     addr, node, dev_name(dev));
94c093198   Grant Likely   of: Merge of_devi...
85
86
  			return;
  		}
94c093198   Grant Likely   of: Merge of_devi...
87

07e461cd7   Grant Likely   of: Ensure unique...
88
89
  		/* format arguments only used if dev_name() resolves to NULL */
  		dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
95e6b1fa3   Rob Herring   of: use kbasename...
90
  			     kbasename(node->full_name), dev_name(dev));
07e461cd7   Grant Likely   of: Ensure unique...
91
92
  		node = node->parent;
  	}
94c093198   Grant Likely   of: Merge of_devi...
93
94
95
96
97
98
99
100
  }
  
  /**
   * of_device_alloc - Allocate and initialize an of_device
   * @np: device node to assign to device
   * @bus_id: Name to assign to the device.  May be null to use default name.
   * @parent: Parent device.
   */
94a0cb1fc   Grant Likely   of/device: Replac...
101
  struct platform_device *of_device_alloc(struct device_node *np,
94c093198   Grant Likely   of: Merge of_devi...
102
103
104
  				  const char *bus_id,
  				  struct device *parent)
  {
94a0cb1fc   Grant Likely   of/device: Replac...
105
  	struct platform_device *dev;
52f6537cb   Andres Salomon   of/irq: remove re...
106
  	int rc, i, num_reg = 0, num_irq;
ac80a51e2   Grant Likely   of/device: popula...
107
  	struct resource *res, temp_res;
6d7e3bf8d   Andy Shevchenko   of: Use PLATFORM_...
108
  	dev = platform_device_alloc("", PLATFORM_DEVID_NONE);
7096d0422   Grant Likely   of/device: Rework...
109
110
111
112
  	if (!dev)
  		return NULL;
  
  	/* count the io and irq resources */
d9c6866be   Rob Herring   of: kill off of_c...
113
114
  	while (of_address_to_resource(np, num_reg, &temp_res) == 0)
  		num_reg++;
52f6537cb   Andres Salomon   of/irq: remove re...
115
  	num_irq = of_irq_count(np);
ac80a51e2   Grant Likely   of/device: popula...
116

ac80a51e2   Grant Likely   of/device: popula...
117
118
  	/* Populate the resource table */
  	if (num_irq || num_reg) {
6396bb221   Kees Cook   treewide: kzalloc...
119
  		res = kcalloc(num_irq + num_reg, sizeof(*res), GFP_KERNEL);
7096d0422   Grant Likely   of/device: Rework...
120
121
122
123
  		if (!res) {
  			platform_device_put(dev);
  			return NULL;
  		}
ac80a51e2   Grant Likely   of/device: popula...
124
125
126
127
128
129
  		dev->num_resources = num_reg + num_irq;
  		dev->resource = res;
  		for (i = 0; i < num_reg; i++, res++) {
  			rc = of_address_to_resource(np, i, res);
  			WARN_ON(rc);
  		}
9ec36cafe   Rob Herring   of/irq: do irq re...
130
  		if (of_irq_to_resource_table(np, res, num_irq) != num_irq)
a613b26a5   Rob Herring   of: Convert to us...
131
132
133
  			pr_debug("not all legacy IRQ resources mapped for %pOFn
  ",
  				 np);
ac80a51e2   Grant Likely   of/device: popula...
134
  	}
94c093198   Grant Likely   of: Merge of_devi...
135
136
  
  	dev->dev.of_node = of_node_get(np);
f94277af0   Robin Murphy   of/platform: Init...
137
  	dev->dev.fwnode = &np->fwnode;
43c0767e1   Grant Likely   of/platform: Move...
138
  	dev->dev.parent = parent ? : &platform_bus;
94c093198   Grant Likely   of: Merge of_devi...
139
140
141
142
143
144
145
146
147
  
  	if (bus_id)
  		dev_set_name(&dev->dev, "%s", bus_id);
  	else
  		of_device_make_bus_id(&dev->dev);
  
  	return dev;
  }
  EXPORT_SYMBOL(of_device_alloc);
591c1ee46   Santosh Shilimkar   of: configure the...
148
  /**
15c3597d6   Grant Likely   dt/platform: allo...
149
   * of_platform_device_create_pdata - Alloc, initialize and register an of_device
5fd200f3b   Grant Likely   of/device: Merge ...
150
151
   * @np: pointer to node to create device for
   * @bus_id: name to assign device
15c3597d6   Grant Likely   dt/platform: allo...
152
   * @platform_data: pointer to populate platform_data pointer with
5fd200f3b   Grant Likely   of/device: Merge ...
153
   * @parent: Linux device model parent device.
cd1e65044   Grant Likely   of/device: Don't ...
154
155
156
   *
   * Returns pointer to created platform device, or NULL if a device was not
   * registered.  Unavailable devices will not get registered.
5fd200f3b   Grant Likely   of/device: Merge ...
157
   */
245d96419   Mark Brown   of/platform: Stat...
158
  static struct platform_device *of_platform_device_create_pdata(
15c3597d6   Grant Likely   dt/platform: allo...
159
160
161
162
  					struct device_node *np,
  					const char *bus_id,
  					void *platform_data,
  					struct device *parent)
5fd200f3b   Grant Likely   of/device: Merge ...
163
  {
94a0cb1fc   Grant Likely   of/device: Replac...
164
  	struct platform_device *dev;
5fd200f3b   Grant Likely   of/device: Merge ...
165

c6e126de4   Pawel Moll   of: Keep track of...
166
167
  	if (!of_device_is_available(np) ||
  	    of_node_test_and_set_flag(np, OF_POPULATED))
cd1e65044   Grant Likely   of/device: Don't ...
168
  		return NULL;
5fd200f3b   Grant Likely   of/device: Merge ...
169
170
  	dev = of_device_alloc(np, bus_id, parent);
  	if (!dev)
c6e126de4   Pawel Moll   of: Keep track of...
171
  		goto err_clear_flag;
5fd200f3b   Grant Likely   of/device: Merge ...
172

a5516219b   Robin Murphy   of/platform: Init...
173
174
175
  	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
  	if (!dev->dev.dma_mask)
  		dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
eca393016   Grant Likely   of: Merge of_plat...
176
  	dev->dev.bus = &platform_bus_type;
15c3597d6   Grant Likely   dt/platform: allo...
177
  	dev->dev.platform_data = platform_data;
c706c239a   Marc Zyngier   of/platform: Assi...
178
  	of_msi_configure(&dev->dev, dev->dev.of_node);
5fd200f3b   Grant Likely   of/device: Merge ...
179

7096d0422   Grant Likely   of/device: Rework...
180
181
  	if (of_device_add(dev) != 0) {
  		platform_device_put(dev);
c6e126de4   Pawel Moll   of: Keep track of...
182
  		goto err_clear_flag;
5fd200f3b   Grant Likely   of/device: Merge ...
183
184
185
  	}
  
  	return dev;
c6e126de4   Pawel Moll   of: Keep track of...
186
187
188
189
  
  err_clear_flag:
  	of_node_clear_flag(np, OF_POPULATED);
  	return NULL;
5fd200f3b   Grant Likely   of/device: Merge ...
190
  }
15c3597d6   Grant Likely   dt/platform: allo...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  
  /**
   * of_platform_device_create - Alloc, initialize and register an of_device
   * @np: pointer to node to create device for
   * @bus_id: name to assign device
   * @parent: Linux device model parent device.
   *
   * Returns pointer to created platform device, or NULL if a device was not
   * registered.  Unavailable devices will not get registered.
   */
  struct platform_device *of_platform_device_create(struct device_node *np,
  					    const char *bus_id,
  					    struct device *parent)
  {
  	return of_platform_device_create_pdata(np, bus_id, NULL, parent);
  }
5fd200f3b   Grant Likely   of/device: Merge ...
207
  EXPORT_SYMBOL(of_platform_device_create);
5de1540b7   Grant Likely   drivers/amba: cre...
208
209
210
211
212
213
214
215
216
  #ifdef CONFIG_ARM_AMBA
  static struct amba_device *of_amba_device_create(struct device_node *node,
  						 const char *bus_id,
  						 void *platform_data,
  						 struct device *parent)
  {
  	struct amba_device *dev;
  	const void *prop;
  	int i, ret;
0d638a07d   Rob Herring   of: Convert to us...
217
218
  	pr_debug("Creating amba device %pOF
  ", node);
5de1540b7   Grant Likely   drivers/amba: cre...
219

c6e126de4   Pawel Moll   of: Keep track of...
220
221
  	if (!of_device_is_available(node) ||
  	    of_node_test_and_set_flag(node, OF_POPULATED))
5de1540b7   Grant Likely   drivers/amba: cre...
222
  		return NULL;
c0f72f8a9   Russell King   ARM: amba: of: co...
223
  	dev = amba_device_alloc(NULL, 0, 0);
606ad42aa   Rob Herring   of: use pr_fmt pr...
224
  	if (!dev)
c6e126de4   Pawel Moll   of: Keep track of...
225
  		goto err_clear_flag;
5de1540b7   Grant Likely   drivers/amba: cre...
226

8c89ef7b6   Linus Walleij   of/platform: init...
227
228
229
  	/* AMBA devices only support a single DMA mask */
  	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
  	dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
5de1540b7   Grant Likely   drivers/amba: cre...
230
  	/* setup generic device info */
5de1540b7   Grant Likely   drivers/amba: cre...
231
  	dev->dev.of_node = of_node_get(node);
f94277af0   Robin Murphy   of/platform: Init...
232
  	dev->dev.fwnode = &node->fwnode;
43c0767e1   Grant Likely   of/platform: Move...
233
  	dev->dev.parent = parent ? : &platform_bus;
5de1540b7   Grant Likely   drivers/amba: cre...
234
235
236
237
238
  	dev->dev.platform_data = platform_data;
  	if (bus_id)
  		dev_set_name(&dev->dev, "%s", bus_id);
  	else
  		of_device_make_bus_id(&dev->dev);
5de1540b7   Grant Likely   drivers/amba: cre...
239
240
241
242
243
244
245
246
247
248
  	/* Allow the HW Peripheral ID to be overridden */
  	prop = of_get_property(node, "arm,primecell-periphid", NULL);
  	if (prop)
  		dev->periphid = of_read_ulong(prop, 1);
  
  	/* Decode the IRQs and address ranges */
  	for (i = 0; i < AMBA_NR_IRQS; i++)
  		dev->irq[i] = irq_of_parse_and_map(node, i);
  
  	ret = of_address_to_resource(node, 0, &dev->res);
2bc552df7   Bartlomiej Zolnierkiewicz   of/platform: add ...
249
  	if (ret) {
0d638a07d   Rob Herring   of: Convert to us...
250
251
252
  		pr_err("amba: of_address_to_resource() failed (%d) for %pOF
  ",
  		       ret, node);
5de1540b7   Grant Likely   drivers/amba: cre...
253
  		goto err_free;
2bc552df7   Bartlomiej Zolnierkiewicz   of/platform: add ...
254
  	}
5de1540b7   Grant Likely   drivers/amba: cre...
255

c0f72f8a9   Russell King   ARM: amba: of: co...
256
  	ret = amba_device_add(dev, &iomem_resource);
2bc552df7   Bartlomiej Zolnierkiewicz   of/platform: add ...
257
  	if (ret) {
0d638a07d   Rob Herring   of: Convert to us...
258
259
260
  		pr_err("amba_device_add() failed (%d) for %pOF
  ",
  		       ret, node);
5de1540b7   Grant Likely   drivers/amba: cre...
261
  		goto err_free;
2bc552df7   Bartlomiej Zolnierkiewicz   of/platform: add ...
262
  	}
5de1540b7   Grant Likely   drivers/amba: cre...
263
264
265
266
  
  	return dev;
  
  err_free:
c0f72f8a9   Russell King   ARM: amba: of: co...
267
  	amba_device_put(dev);
c6e126de4   Pawel Moll   of: Keep track of...
268
269
  err_clear_flag:
  	of_node_clear_flag(node, OF_POPULATED);
5de1540b7   Grant Likely   drivers/amba: cre...
270
271
272
273
274
275
276
277
278
279
280
  	return NULL;
  }
  #else /* CONFIG_ARM_AMBA */
  static struct amba_device *of_amba_device_create(struct device_node *node,
  						 const char *bus_id,
  						 void *platform_data,
  						 struct device *parent)
  {
  	return NULL;
  }
  #endif /* CONFIG_ARM_AMBA */
5fd200f3b   Grant Likely   of/device: Merge ...
281
  /**
15c3597d6   Grant Likely   dt/platform: allo...
282
283
284
285
286
   * of_devname_lookup() - Given a device node, lookup the preferred Linux name
   */
  static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *lookup,
  				 struct device_node *np)
  {
fc5cf80ac   Tony Lindgren   of/platform: Allo...
287
  	const struct of_dev_auxdata *auxdata;
15c3597d6   Grant Likely   dt/platform: allo...
288
  	struct resource res;
fc5cf80ac   Tony Lindgren   of/platform: Allo...
289
  	int compatible = 0;
303f59d1a   Olof Johansson   dt/platform: mino...
290
291
292
  
  	if (!lookup)
  		return NULL;
fc5cf80ac   Tony Lindgren   of/platform: Allo...
293
294
295
  	auxdata = lookup;
  	for (; auxdata->compatible; auxdata++) {
  		if (!of_device_is_compatible(np, auxdata->compatible))
303f59d1a   Olof Johansson   dt/platform: mino...
296
  			continue;
fc5cf80ac   Tony Lindgren   of/platform: Allo...
297
  		compatible++;
84774e615   Lee Jones   of: address: Don'...
298
  		if (!of_address_to_resource(np, 0, &res))
fc5cf80ac   Tony Lindgren   of/platform: Allo...
299
  			if (res.start != auxdata->phys_addr)
84774e615   Lee Jones   of: address: Don'...
300
  				continue;
0d638a07d   Rob Herring   of: Convert to us...
301
302
  		pr_debug("%pOF: devname=%s
  ", np, auxdata->name);
fc5cf80ac   Tony Lindgren   of/platform: Allo...
303
304
305
306
307
308
309
310
311
312
313
314
  		return auxdata;
  	}
  
  	if (!compatible)
  		return NULL;
  
  	/* Try compatible match if no phys_addr and name are specified */
  	auxdata = lookup;
  	for (; auxdata->compatible; auxdata++) {
  		if (!of_device_is_compatible(np, auxdata->compatible))
  			continue;
  		if (!auxdata->phys_addr && !auxdata->name) {
0d638a07d   Rob Herring   of: Convert to us...
315
316
  			pr_debug("%pOF: compatible match
  ", np);
fc5cf80ac   Tony Lindgren   of/platform: Allo...
317
318
  			return auxdata;
  		}
15c3597d6   Grant Likely   dt/platform: allo...
319
  	}
303f59d1a   Olof Johansson   dt/platform: mino...
320

15c3597d6   Grant Likely   dt/platform: allo...
321
322
323
324
  	return NULL;
  }
  
  /**
38e9e21da   Grant Likely   dt: Refactor of_p...
325
   * of_platform_bus_create() - Create a device for a node and its children.
5fd200f3b   Grant Likely   of/device: Merge ...
326
   * @bus: device node of the bus to instantiate
1eed4c077   Grant Likely   dt: eliminate OF_...
327
   * @matches: match table for bus nodes
303f59d1a   Olof Johansson   dt/platform: mino...
328
   * @lookup: auxdata table for matching id and platform_data with device nodes
38e9e21da   Grant Likely   dt: Refactor of_p...
329
   * @parent: parent for new device, or NULL for top level.
303f59d1a   Olof Johansson   dt/platform: mino...
330
   * @strict: require compatible property
38e9e21da   Grant Likely   dt: Refactor of_p...
331
332
333
   *
   * Creates a platform_device for the provided device_node, and optionally
   * recursively create devices for all the child nodes.
5fd200f3b   Grant Likely   of/device: Merge ...
334
   */
38e9e21da   Grant Likely   dt: Refactor of_p...
335
  static int of_platform_bus_create(struct device_node *bus,
5fd200f3b   Grant Likely   of/device: Merge ...
336
  				  const struct of_device_id *matches,
15c3597d6   Grant Likely   dt/platform: allo...
337
  				  const struct of_dev_auxdata *lookup,
29d4f8a49   Grant Likely   dt: add of_platfo...
338
  				  struct device *parent, bool strict)
5fd200f3b   Grant Likely   of/device: Merge ...
339
  {
15c3597d6   Grant Likely   dt/platform: allo...
340
  	const struct of_dev_auxdata *auxdata;
5fd200f3b   Grant Likely   of/device: Merge ...
341
  	struct device_node *child;
94a0cb1fc   Grant Likely   of/device: Replac...
342
  	struct platform_device *dev;
15c3597d6   Grant Likely   dt/platform: allo...
343
344
  	const char *bus_id = NULL;
  	void *platform_data = NULL;
5fd200f3b   Grant Likely   of/device: Merge ...
345
  	int rc = 0;
29d4f8a49   Grant Likely   dt: add of_platfo...
346
347
  	/* Make sure it has a compatible property */
  	if (strict && (!of_get_property(bus, "compatible", NULL))) {
0d638a07d   Rob Herring   of: Convert to us...
348
349
350
  		pr_debug("%s() - skipping %pOF, no compatible prop
  ",
  			 __func__, bus);
29d4f8a49   Grant Likely   dt: add of_platfo...
351
352
  		return 0;
  	}
4550fe637   Viresh Kumar   of: Don't create ...
353
354
355
356
357
358
  	/* Skip nodes for which we don't want to create devices */
  	if (unlikely(of_match_node(of_skipped_node_table, bus))) {
  		pr_debug("%s() - skipping %pOF node
  ", __func__, bus);
  		return 0;
  	}
44a7185c2   Kefeng Wang   of/platform: Add ...
359
  	if (of_node_check_flag(bus, OF_POPULATED_BUS)) {
0d638a07d   Rob Herring   of: Convert to us...
360
361
362
  		pr_debug("%s() - skipping %pOF, already populated
  ",
  			__func__, bus);
44a7185c2   Kefeng Wang   of/platform: Add ...
363
364
  		return 0;
  	}
15c3597d6   Grant Likely   dt/platform: allo...
365
366
367
368
369
  	auxdata = of_dev_lookup(lookup, bus);
  	if (auxdata) {
  		bus_id = auxdata->name;
  		platform_data = auxdata->platform_data;
  	}
5de1540b7   Grant Likely   drivers/amba: cre...
370
  	if (of_device_is_compatible(bus, "arm,primecell")) {
2bc552df7   Bartlomiej Zolnierkiewicz   of/platform: add ...
371
372
373
374
  		/*
  		 * Don't return an error here to keep compatibility with older
  		 * device tree files.
  		 */
15c3597d6   Grant Likely   dt/platform: allo...
375
  		of_amba_device_create(bus, bus_id, platform_data, parent);
5de1540b7   Grant Likely   drivers/amba: cre...
376
377
  		return 0;
  	}
15c3597d6   Grant Likely   dt/platform: allo...
378
  	dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);
38e9e21da   Grant Likely   dt: Refactor of_p...
379
380
  	if (!dev || !of_match_node(matches, bus))
  		return 0;
5fd200f3b   Grant Likely   of/device: Merge ...
381
  	for_each_child_of_node(bus, child) {
0d638a07d   Rob Herring   of: Convert to us...
382
383
  		pr_debug("   create child: %pOF
  ", child);
15c3597d6   Grant Likely   dt/platform: allo...
384
  		rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict);
5fd200f3b   Grant Likely   of/device: Merge ...
385
386
387
388
389
  		if (rc) {
  			of_node_put(child);
  			break;
  		}
  	}
75f353b61   Grant Likely   of/platform: Fix ...
390
  	of_node_set_flag(bus, OF_POPULATED_BUS);
5fd200f3b   Grant Likely   of/device: Merge ...
391
392
393
394
  	return rc;
  }
  
  /**
38e9e21da   Grant Likely   dt: Refactor of_p...
395
   * of_platform_bus_probe() - Probe the device-tree for platform buses
5fd200f3b   Grant Likely   of/device: Merge ...
396
   * @root: parent of the first level to probe or NULL for the root of the tree
1eed4c077   Grant Likely   dt: eliminate OF_...
397
   * @matches: match table for bus nodes
5fd200f3b   Grant Likely   of/device: Merge ...
398
399
400
401
402
403
404
405
406
407
   * @parent: parent to hook devices from, NULL for toplevel
   *
   * Note that children of the provided root are not instantiated as devices
   * unless the specified root itself matches the bus list and is not NULL.
   */
  int of_platform_bus_probe(struct device_node *root,
  			  const struct of_device_id *matches,
  			  struct device *parent)
  {
  	struct device_node *child;
5fd200f3b   Grant Likely   of/device: Merge ...
408
  	int rc = 0;
1eed4c077   Grant Likely   dt: eliminate OF_...
409
410
  	root = root ? of_node_get(root) : of_find_node_by_path("/");
  	if (!root)
60d599133   Grant Likely   of/flattree: Fix ...
411
  		return -EINVAL;
5fd200f3b   Grant Likely   of/device: Merge ...
412

44a7185c2   Kefeng Wang   of/platform: Add ...
413
414
  	pr_debug("%s()
  ", __func__);
0d638a07d   Rob Herring   of: Convert to us...
415
416
  	pr_debug(" starting at: %pOF
  ", root);
5fd200f3b   Grant Likely   of/device: Merge ...
417

1eed4c077   Grant Likely   dt: eliminate OF_...
418
  	/* Do a self check of bus type, if there's a match, create children */
5fd200f3b   Grant Likely   of/device: Merge ...
419
  	if (of_match_node(matches, root)) {
15c3597d6   Grant Likely   dt/platform: allo...
420
  		rc = of_platform_bus_create(root, matches, NULL, parent, false);
38e9e21da   Grant Likely   dt: Refactor of_p...
421
  	} else for_each_child_of_node(root, child) {
5fd200f3b   Grant Likely   of/device: Merge ...
422
423
  		if (!of_match_node(matches, child))
  			continue;
15c3597d6   Grant Likely   dt/platform: allo...
424
  		rc = of_platform_bus_create(child, matches, NULL, parent, false);
7fad948a7   Julia Lawall   of/platform: add ...
425
426
  		if (rc) {
  			of_node_put(child);
5fd200f3b   Grant Likely   of/device: Merge ...
427
  			break;
7fad948a7   Julia Lawall   of/platform: add ...
428
  		}
5fd200f3b   Grant Likely   of/device: Merge ...
429
  	}
38e9e21da   Grant Likely   dt: Refactor of_p...
430

5fd200f3b   Grant Likely   of/device: Merge ...
431
432
433
434
  	of_node_put(root);
  	return rc;
  }
  EXPORT_SYMBOL(of_platform_bus_probe);
29d4f8a49   Grant Likely   dt: add of_platfo...
435
436
437
438
439
  
  /**
   * of_platform_populate() - Populate platform_devices from device tree data
   * @root: parent of the first level to probe or NULL for the root of the tree
   * @matches: match table, NULL to use the default
92039ed12   Javi Merino   of: add missing d...
440
   * @lookup: auxdata table for matching id and platform_data with device nodes
29d4f8a49   Grant Likely   dt: add of_platfo...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
   * @parent: parent to hook devices from, NULL for toplevel
   *
   * Similar to of_platform_bus_probe(), this function walks the device tree
   * and creates devices from nodes.  It differs in that it follows the modern
   * convention of requiring all device nodes to have a 'compatible' property,
   * and it is suitable for creating devices which are children of the root
   * node (of_platform_bus_probe will only create children of the root which
   * are selected by the @matches argument).
   *
   * New board support should be using this function instead of
   * of_platform_bus_probe().
   *
   * Returns 0 on success, < 0 on failure.
   */
  int of_platform_populate(struct device_node *root,
  			const struct of_device_id *matches,
15c3597d6   Grant Likely   dt/platform: allo...
457
  			const struct of_dev_auxdata *lookup,
29d4f8a49   Grant Likely   dt: add of_platfo...
458
459
460
461
462
463
464
465
  			struct device *parent)
  {
  	struct device_node *child;
  	int rc = 0;
  
  	root = root ? of_node_get(root) : of_find_node_by_path("/");
  	if (!root)
  		return -EINVAL;
44a7185c2   Kefeng Wang   of/platform: Add ...
466
467
  	pr_debug("%s()
  ", __func__);
0d638a07d   Rob Herring   of: Convert to us...
468
469
  	pr_debug(" starting at: %pOF
  ", root);
44a7185c2   Kefeng Wang   of/platform: Add ...
470

5e6669387   Saravana Kannan   of/platform: Paus...
471
  	device_links_supplier_sync_state_pause();
29d4f8a49   Grant Likely   dt: add of_platfo...
472
  	for_each_child_of_node(root, child) {
15c3597d6   Grant Likely   dt/platform: allo...
473
  		rc = of_platform_bus_create(child, matches, lookup, parent, true);
7fad948a7   Julia Lawall   of/platform: add ...
474
475
  		if (rc) {
  			of_node_put(child);
29d4f8a49   Grant Likely   dt: add of_platfo...
476
  			break;
7fad948a7   Julia Lawall   of/platform: add ...
477
  		}
29d4f8a49   Grant Likely   dt: add of_platfo...
478
  	}
5e6669387   Saravana Kannan   of/platform: Paus...
479
  	device_links_supplier_sync_state_resume();
2d0747c4b   Grant Likely   of: Properly set ...
480
  	of_node_set_flag(root, OF_POPULATED_BUS);
29d4f8a49   Grant Likely   dt: add of_platfo...
481
482
483
484
  
  	of_node_put(root);
  	return rc;
  }
e001f1c8e   Stephen Warren   of: export of_pla...
485
  EXPORT_SYMBOL_GPL(of_platform_populate);
c6e126de4   Pawel Moll   of: Keep track of...
486

43443ad69   Hauke Mehrtens   of/platform: add ...
487
488
489
490
491
492
493
494
  int of_platform_default_populate(struct device_node *root,
  				 const struct of_dev_auxdata *lookup,
  				 struct device *parent)
  {
  	return of_platform_populate(root, of_default_bus_match_table, lookup,
  				    parent);
  }
  EXPORT_SYMBOL_GPL(of_platform_default_populate);
fc520f8b4   Kevin Hao   of/platform: disa...
495
  #ifndef CONFIG_PPC
a50ff19d0   Bjorn Andersson   of/platform: Gene...
496
  static const struct of_device_id reserved_mem_matches[] = {
d1de6d6c6   Bjorn Andersson   soc: qcom: Remote...
497
  	{ .compatible = "qcom,rmtfs-mem" },
312416d91   Mahesh Sivasubramanian   drivers: qcom: ad...
498
  	{ .compatible = "qcom,cmd-db" },
a50ff19d0   Bjorn Andersson   of/platform: Gene...
499
500
501
  	{ .compatible = "ramoops" },
  	{}
  };
44a7185c2   Kefeng Wang   of/platform: Add ...
502
503
  static int __init of_platform_default_populate_init(void)
  {
529182e20   Kees Cook   ramoops: use DT r...
504
  	struct device_node *node;
ee9b280e1   Saravana Kannan   of/platform: Unco...
505
  	device_links_supplier_sync_state_pause();
529182e20   Kees Cook   ramoops: use DT r...
506
507
508
509
  	if (!of_have_populated_dt())
  		return -ENODEV;
  
  	/*
a50ff19d0   Bjorn Andersson   of/platform: Gene...
510
511
512
  	 * Handle certain compatibles explicitly, since we don't want to create
  	 * platform_devices for every node in /reserved-memory with a
  	 * "compatible",
529182e20   Kees Cook   ramoops: use DT r...
513
  	 */
a50ff19d0   Bjorn Andersson   of/platform: Gene...
514
515
  	for_each_matching_node(node, reserved_mem_matches)
  		of_platform_device_create(node, NULL, NULL);
529182e20   Kees Cook   ramoops: use DT r...
516

3aa0582fd   Sudeep Holla   of: platform: pop...
517
  	node = of_find_node_by_path("/firmware");
e2105ca8b   Sudeep Holla   of: platform: fix...
518
  	if (node) {
3aa0582fd   Sudeep Holla   of: platform: pop...
519
  		of_platform_populate(node, NULL, NULL, NULL);
e2105ca8b   Sudeep Holla   of: platform: fix...
520
521
  		of_node_put(node);
  	}
3aa0582fd   Sudeep Holla   of: platform: pop...
522

529182e20   Kees Cook   ramoops: use DT r...
523
524
  	/* Populate everything else. */
  	of_platform_default_populate(NULL, NULL, NULL);
44a7185c2   Kefeng Wang   of/platform: Add ...
525
526
527
528
  
  	return 0;
  }
  arch_initcall_sync(of_platform_default_populate_init);
5e6669387   Saravana Kannan   of/platform: Paus...
529
530
531
  
  static int __init of_platform_sync_state_init(void)
  {
ee9b280e1   Saravana Kannan   of/platform: Unco...
532
  	device_links_supplier_sync_state_resume();
5e6669387   Saravana Kannan   of/platform: Paus...
533
534
535
  	return 0;
  }
  late_initcall_sync(of_platform_sync_state_init);
fc520f8b4   Kevin Hao   of/platform: disa...
536
  #endif
44a7185c2   Kefeng Wang   of/platform: Add ...
537

c2372c204   Jan Glauber   of/platform: Make...
538
  int of_platform_device_destroy(struct device *dev, void *data)
c6e126de4   Pawel Moll   of: Keep track of...
539
  {
c6e126de4   Pawel Moll   of: Keep track of...
540
  	/* Do not touch devices not populated from the device tree */
75f353b61   Grant Likely   of/platform: Fix ...
541
  	if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED))
c6e126de4   Pawel Moll   of: Keep track of...
542
  		return 0;
c6e126de4   Pawel Moll   of: Keep track of...
543

75f353b61   Grant Likely   of/platform: Fix ...
544
545
546
  	/* Recurse for any nodes that were treated as busses */
  	if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS))
  		device_for_each_child(dev, NULL, of_platform_device_destroy);
c6e126de4   Pawel Moll   of: Keep track of...
547

522811e94   Srinivas Kandagatla   of: platform: sto...
548
549
  	of_node_clear_flag(dev->of_node, OF_POPULATED);
  	of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
c6e126de4   Pawel Moll   of: Keep track of...
550
551
552
553
554
555
  	if (dev->bus == &platform_bus_type)
  		platform_device_unregister(to_platform_device(dev));
  #ifdef CONFIG_ARM_AMBA
  	else if (dev->bus == &amba_bustype)
  		amba_device_unregister(to_amba_device(dev));
  #endif
c6e126de4   Pawel Moll   of: Keep track of...
556

c6e126de4   Pawel Moll   of: Keep track of...
557
558
  	return 0;
  }
c2372c204   Jan Glauber   of/platform: Make...
559
  EXPORT_SYMBOL_GPL(of_platform_device_destroy);
c6e126de4   Pawel Moll   of: Keep track of...
560
561
562
  
  /**
   * of_platform_depopulate() - Remove devices populated from device tree
75f353b61   Grant Likely   of/platform: Fix ...
563
   * @parent: device which children will be removed
c6e126de4   Pawel Moll   of: Keep track of...
564
565
566
567
568
   *
   * Complementary to of_platform_populate(), this function removes children
   * of the given device (and, recurrently, their children) that have been
   * created from their respective device tree nodes (and only those,
   * leaving others - eg. manually created - unharmed).
c6e126de4   Pawel Moll   of: Keep track of...
569
   */
75f353b61   Grant Likely   of/platform: Fix ...
570
  void of_platform_depopulate(struct device *parent)
c6e126de4   Pawel Moll   of: Keep track of...
571
  {
2d0747c4b   Grant Likely   of: Properly set ...
572
573
574
575
  	if (parent->of_node && of_node_check_flag(parent->of_node, OF_POPULATED_BUS)) {
  		device_for_each_child(parent, NULL, of_platform_device_destroy);
  		of_node_clear_flag(parent->of_node, OF_POPULATED_BUS);
  	}
c6e126de4   Pawel Moll   of: Keep track of...
576
577
  }
  EXPORT_SYMBOL_GPL(of_platform_depopulate);
38b0b219f   Benjamin Gaignard   of: add devm_ fun...
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
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  static void devm_of_platform_populate_release(struct device *dev, void *res)
  {
  	of_platform_depopulate(*(struct device **)res);
  }
  
  /**
   * devm_of_platform_populate() - Populate platform_devices from device tree data
   * @dev: device that requested to populate from device tree data
   *
   * Similar to of_platform_populate(), but will automatically call
   * of_platform_depopulate() when the device is unbound from the bus.
   *
   * Returns 0 on success, < 0 on failure.
   */
  int devm_of_platform_populate(struct device *dev)
  {
  	struct device **ptr;
  	int ret;
  
  	if (!dev)
  		return -EINVAL;
  
  	ptr = devres_alloc(devm_of_platform_populate_release,
  			   sizeof(*ptr), GFP_KERNEL);
  	if (!ptr)
  		return -ENOMEM;
  
  	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
  	if (ret) {
  		devres_free(ptr);
  	} else {
  		*ptr = dev;
  		devres_add(dev, ptr);
  	}
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(devm_of_platform_populate);
  
  static int devm_of_platform_match(struct device *dev, void *res, void *data)
  {
  	struct device **ptr = res;
  
  	if (!ptr) {
  		WARN_ON(!ptr);
  		return 0;
  	}
  
  	return *ptr == data;
  }
  
  /**
   * devm_of_platform_depopulate() - Remove devices populated from device tree
   * @dev: device that requested to depopulate from device tree data
   *
   * Complementary to devm_of_platform_populate(), this function removes children
   * of the given device (and, recurrently, their children) that have been
   * created from their respective device tree nodes (and only those,
   * leaving others - eg. manually created - unharmed).
   */
  void devm_of_platform_depopulate(struct device *dev)
  {
  	int ret;
  
  	ret = devres_release(dev, devm_of_platform_populate_release,
  			     devm_of_platform_match, dev);
  
  	WARN_ON(ret);
  }
  EXPORT_SYMBOL_GPL(devm_of_platform_depopulate);
801d728c1   Pantelis Antoniou   of/reconfig: Add ...
648
649
650
651
652
653
654
655
656
657
658
659
660
  #ifdef CONFIG_OF_DYNAMIC
  static int of_platform_notify(struct notifier_block *nb,
  				unsigned long action, void *arg)
  {
  	struct of_reconfig_data *rd = arg;
  	struct platform_device *pdev_parent, *pdev;
  	bool children_left;
  
  	switch (of_reconfig_get_state_change(action, rd)) {
  	case OF_RECONFIG_CHANGE_ADD:
  		/* verify that the parent is a bus */
  		if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS))
  			return NOTIFY_OK;	/* not for us */
15204ab1e   Pantelis Antoniou   of/platform: Hand...
661
662
663
  		/* already populated? (driver using of_populate manually) */
  		if (of_node_check_flag(rd->dn, OF_POPULATED))
  			return NOTIFY_OK;
801d728c1   Pantelis Antoniou   of/reconfig: Add ...
664
665
666
667
668
669
670
  		/* pdev_parent may be NULL when no bus platform device */
  		pdev_parent = of_find_device_by_node(rd->dn->parent);
  		pdev = of_platform_device_create(rd->dn, NULL,
  				pdev_parent ? &pdev_parent->dev : NULL);
  		of_dev_put(pdev_parent);
  
  		if (pdev == NULL) {
0d638a07d   Rob Herring   of: Convert to us...
671
672
673
  			pr_err("%s: failed to create for '%pOF'
  ",
  					__func__, rd->dn);
801d728c1   Pantelis Antoniou   of/reconfig: Add ...
674
675
676
677
678
679
  			/* of_platform_device_create tosses the error code */
  			return notifier_from_errno(-EINVAL);
  		}
  		break;
  
  	case OF_RECONFIG_CHANGE_REMOVE:
15204ab1e   Pantelis Antoniou   of/platform: Hand...
680
681
682
683
  
  		/* already depopulated? */
  		if (!of_node_check_flag(rd->dn, OF_POPULATED))
  			return NOTIFY_OK;
801d728c1   Pantelis Antoniou   of/reconfig: Add ...
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
  		/* find our device by node */
  		pdev = of_find_device_by_node(rd->dn);
  		if (pdev == NULL)
  			return NOTIFY_OK;	/* no? not meant for us */
  
  		/* unregister takes one ref away */
  		of_platform_device_destroy(&pdev->dev, &children_left);
  
  		/* and put the reference of the find */
  		of_dev_put(pdev);
  		break;
  	}
  
  	return NOTIFY_OK;
  }
  
  static struct notifier_block platform_of_notifier = {
  	.notifier_call = of_platform_notify,
  };
  
  void of_platform_register_reconfig_notifier(void)
  {
  	WARN_ON(of_reconfig_notifier_register(&platform_of_notifier));
  }
  #endif /* CONFIG_OF_DYNAMIC */
964dba283   Grant Likely   devicetree: Add e...
709
  #endif /* CONFIG_OF_ADDRESS */