dt/platform: allow device name to be overridden
Some platform code has specific requirements on the naming of devices. This patch allows callers of of_platform_populate() to provide a device name lookup table. Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
		
					parent
					
						
							
								5de1540b7b
							
						
					
				
			
			
				commit
				
					
						15c3597d6e
					
				
			
		
					 2 changed files with 98 additions and 10 deletions
				
			
		|  | @ -177,17 +177,20 @@ struct platform_device *of_device_alloc(struct device_node *np, | |||
| EXPORT_SYMBOL(of_device_alloc); | ||||
| 
 | ||||
| /**
 | ||||
|  * of_platform_device_create - Alloc, initialize and register an of_device | ||||
|  * of_platform_device_create_pdata - Alloc, initialize and register an of_device | ||||
|  * @np: pointer to node to create device for | ||||
|  * @bus_id: name to assign device | ||||
|  * @platform_data: pointer to populate platform_data pointer with | ||||
|  * @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) | ||||
| struct platform_device *of_platform_device_create_pdata( | ||||
| 					struct device_node *np, | ||||
| 					const char *bus_id, | ||||
| 					void *platform_data, | ||||
| 					struct device *parent) | ||||
| { | ||||
| 	struct platform_device *dev; | ||||
| 
 | ||||
|  | @ -203,6 +206,7 @@ struct platform_device *of_platform_device_create(struct device_node *np, | |||
| #endif | ||||
| 	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); | ||||
| 	dev->dev.bus = &platform_bus_type; | ||||
| 	dev->dev.platform_data = platform_data; | ||||
| 
 | ||||
| 	/* We do not fill the DMA ops for platform devices by default.
 | ||||
| 	 * This is currently the responsibility of the platform code | ||||
|  | @ -216,6 +220,22 @@ struct platform_device *of_platform_device_create(struct device_node *np, | |||
| 
 | ||||
| 	return dev; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * 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); | ||||
| } | ||||
| EXPORT_SYMBOL(of_platform_device_create); | ||||
| 
 | ||||
| #ifdef CONFIG_ARM_AMBA | ||||
|  | @ -283,6 +303,28 @@ static struct amba_device *of_amba_device_create(struct device_node *node, | |||
| } | ||||
| #endif /* CONFIG_ARM_AMBA */ | ||||
| 
 | ||||
| /**
 | ||||
|  * 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) | ||||
| { | ||||
| 	struct resource res; | ||||
| 	if (lookup) { | ||||
| 		for(; lookup->name != NULL; lookup++) { | ||||
| 			if (!of_device_is_compatible(np, lookup->compatible)) | ||||
| 				continue; | ||||
| 			if (of_address_to_resource(np, 0, &res)) | ||||
| 				continue; | ||||
| 			if (res.start != lookup->phys_addr) | ||||
| 				continue; | ||||
| 			pr_debug("%s: devname=%s\n", np->full_name, lookup->name); | ||||
| 			return lookup; | ||||
| 		} | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * of_platform_bus_create() - Create a device for a node and its children. | ||||
|  * @bus: device node of the bus to instantiate | ||||
|  | @ -295,10 +337,14 @@ static struct amba_device *of_amba_device_create(struct device_node *node, | |||
|  */ | ||||
| static int of_platform_bus_create(struct device_node *bus, | ||||
| 				  const struct of_device_id *matches, | ||||
| 				  const struct of_dev_auxdata *lookup, | ||||
| 				  struct device *parent, bool strict) | ||||
| { | ||||
| 	const struct of_dev_auxdata *auxdata; | ||||
| 	struct device_node *child; | ||||
| 	struct platform_device *dev; | ||||
| 	const char *bus_id = NULL; | ||||
| 	void *platform_data = NULL; | ||||
| 	int rc = 0; | ||||
| 
 | ||||
| 	/* Make sure it has a compatible property */ | ||||
|  | @ -308,18 +354,24 @@ static int of_platform_bus_create(struct device_node *bus, | |||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	auxdata = of_dev_lookup(lookup, bus); | ||||
| 	if (auxdata) { | ||||
| 		bus_id = auxdata->name; | ||||
| 		platform_data = auxdata->platform_data; | ||||
| 	} | ||||
| 
 | ||||
| 	if (of_device_is_compatible(bus, "arm,primecell")) { | ||||
| 		of_amba_device_create(bus, NULL, NULL, parent); | ||||
| 		of_amba_device_create(bus, bus_id, platform_data, parent); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	dev = of_platform_device_create(bus, NULL, parent); | ||||
| 	dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent); | ||||
| 	if (!dev || !of_match_node(matches, bus)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	for_each_child_of_node(bus, child) { | ||||
| 		pr_debug("   create child: %s\n", child->full_name); | ||||
| 		rc = of_platform_bus_create(child, matches, &dev->dev, strict); | ||||
| 		rc = of_platform_bus_create(child, matches, lookup, &dev->dev, strict); | ||||
| 		if (rc) { | ||||
| 			of_node_put(child); | ||||
| 			break; | ||||
|  | @ -353,11 +405,11 @@ int of_platform_bus_probe(struct device_node *root, | |||
| 
 | ||||
| 	/* Do a self check of bus type, if there's a match, create children */ | ||||
| 	if (of_match_node(matches, root)) { | ||||
| 		rc = of_platform_bus_create(root, matches, parent, false); | ||||
| 		rc = of_platform_bus_create(root, matches, NULL, parent, false); | ||||
| 	} else for_each_child_of_node(root, child) { | ||||
| 		if (!of_match_node(matches, child)) | ||||
| 			continue; | ||||
| 		rc = of_platform_bus_create(child, matches, parent, false); | ||||
| 		rc = of_platform_bus_create(child, matches, NULL, parent, false); | ||||
| 		if (rc) | ||||
| 			break; | ||||
| 	} | ||||
|  | @ -387,6 +439,7 @@ EXPORT_SYMBOL(of_platform_bus_probe); | |||
|  */ | ||||
| int of_platform_populate(struct device_node *root, | ||||
| 			const struct of_device_id *matches, | ||||
| 			const struct of_dev_auxdata *lookup, | ||||
| 			struct device *parent) | ||||
| { | ||||
| 	struct device_node *child; | ||||
|  | @ -397,7 +450,7 @@ int of_platform_populate(struct device_node *root, | |||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	for_each_child_of_node(root, child) { | ||||
| 		rc = of_platform_bus_create(child, matches, parent, true); | ||||
| 		rc = of_platform_bus_create(child, matches, lookup, parent, true); | ||||
| 		if (rc) | ||||
| 			break; | ||||
| 	} | ||||
|  |  | |||
|  | @ -19,6 +19,40 @@ | |||
| #include <linux/of_device.h> | ||||
| #include <linux/platform_device.h> | ||||
| 
 | ||||
| /**
 | ||||
|  * struct of_dev_auxdata - lookup table entry for device names & platform_data | ||||
|  * @compatible: compatible value of node to match against node | ||||
|  * @phys_addr: Start address of registers to match against node | ||||
|  * @name: Name to assign for matching nodes | ||||
|  * @platform_data: platform_data to assign for matching nodes | ||||
|  * | ||||
|  * This lookup table allows the caller of of_platform_populate() to override | ||||
|  * the names of devices when creating devices from the device tree.  The table | ||||
|  * should be terminated with an empty entry.  It also allows the platform_data | ||||
|  * pointer to be set. | ||||
|  * | ||||
|  * The reason for this functionality is that some Linux infrastructure uses | ||||
|  * the device name to look up a specific device, but the Linux-specific names | ||||
|  * are not encoded into the device tree, so the kernel needs to provide specific | ||||
|  * values. | ||||
|  * | ||||
|  * Note: Using an auxdata lookup table should be considered a last resort when | ||||
|  * converting a platform to use the DT.  Normally the automatically generated | ||||
|  * device name will not matter, and drivers should obtain data from the device | ||||
|  * node instead of from an anonymouns platform_data pointer. | ||||
|  */ | ||||
| struct of_dev_auxdata { | ||||
| 	char *compatible; | ||||
| 	resource_size_t phys_addr; | ||||
| 	char *name; | ||||
| 	void *platform_data; | ||||
| }; | ||||
| 
 | ||||
| /* Macro to simplify populating a lookup table */ | ||||
| #define OF_DEV_AUXDATA(_compat,_phys,_name,_pdata) \ | ||||
| 	{ .compatible = _compat, .phys_addr = _phys, .name = _name, \ | ||||
| 	  .platform_data = _pdata } | ||||
| 
 | ||||
| /**
 | ||||
|  * of_platform_driver - Legacy of-aware driver for platform devices. | ||||
|  * | ||||
|  | @ -59,6 +93,7 @@ extern int of_platform_bus_probe(struct device_node *root, | |||
| 				 struct device *parent); | ||||
| extern int of_platform_populate(struct device_node *root, | ||||
| 				const struct of_device_id *matches, | ||||
| 				const struct of_dev_auxdata *lookup, | ||||
| 				struct device *parent); | ||||
| #endif /* !CONFIG_SPARC */ | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Grant Likely
				Grant Likely