2007-05-02 20:38:57 +04:00
/*
* 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
*
* 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/errno.h>
2007-10-18 08:17:42 +04:00
# include <linux/module.h>
2011-06-21 20:59:34 +04:00
# include <linux/amba/bus.h>
2007-05-02 20:38:57 +04:00
# include <linux/device.h>
2010-06-08 17:48:13 +04:00
# include <linux/dma-mapping.h>
2010-06-08 17:48:20 +04:00
# include <linux/slab.h>
2010-06-08 17:48:26 +04:00
# include <linux/of_address.h>
2007-05-02 20:38:57 +04:00
# include <linux/of_device.h>
2010-06-08 17:48:26 +04:00
# include <linux/of_irq.h>
2007-05-02 20:38:57 +04:00
# include <linux/of_platform.h>
2010-06-08 17:48:21 +04:00
# include <linux/platform_device.h>
2011-06-21 20:59:34 +04:00
const struct of_device_id of_default_bus_match_table [ ] = {
{ . compatible = " simple-bus " , } ,
# ifdef CONFIG_ARM_AMBA
{ . compatible = " arm,amba-bus " , } ,
# endif /* CONFIG_ARM_AMBA */
{ } /* Empty terminated list */
} ;
2010-07-23 21:19:35 +04:00
static int of_dev_node_match ( struct device * dev , void * data )
{
return dev - > of_node = = data ;
}
/**
* of_find_device_by_node - Find the platform_device associated with a node
* @ np : Pointer to device tree node
*
* Returns platform_device pointer , or NULL if not found
*/
struct platform_device * of_find_device_by_node ( struct device_node * np )
{
struct device * dev ;
dev = bus_find_device ( & platform_bus_type , NULL , np , of_dev_node_match ) ;
return dev ? to_platform_device ( dev ) : NULL ;
}
EXPORT_SYMBOL ( of_find_device_by_node ) ;
2010-07-15 09:51:43 +04:00
# if defined(CONFIG_PPC_DCR)
# include <asm/dcr.h>
# endif
2012-02-25 01:58:34 +04:00
# ifdef CONFIG_OF_ADDRESS
2010-06-08 17:48:13 +04:00
/*
* 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 .
*/
2010-06-08 17:48:14 +04:00
/**
* 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
*
* This routine will first try using either the dcr - reg or the reg property
* value to derive a unique name . As a last resort it will use the node
* name followed by a unique number .
*/
2010-07-24 01:04:01 +04:00
void of_device_make_bus_id ( struct device * dev )
2010-06-08 17:48:14 +04:00
{
static atomic_t bus_no_reg_magic ;
struct device_node * node = dev - > of_node ;
2012-10-09 04:42:11 +04:00
const __be32 * reg ;
2010-06-08 17:48:14 +04:00
u64 addr ;
2012-07-26 03:34:37 +04:00
const __be32 * addrp ;
2010-06-08 17:48:14 +04:00
int magic ;
# ifdef CONFIG_PPC_DCR
/*
* If it ' s a DCR based device , use ' d ' for native DCRs
* and ' D ' for MMIO DCRs .
*/
reg = of_get_property ( node , " dcr-reg " , NULL ) ;
if ( reg ) {
# ifdef CONFIG_PPC_DCR_NATIVE
dev_set_name ( dev , " d%x.%s " , * reg , node - > name ) ;
# else /* CONFIG_PPC_DCR_NATIVE */
u64 addr = of_translate_dcr_address ( node , * reg , NULL ) ;
if ( addr ! = OF_BAD_ADDR ) {
dev_set_name ( dev , " D%llx.%s " ,
( unsigned long long ) addr , node - > name ) ;
return ;
}
# endif /* !CONFIG_PPC_DCR_NATIVE */
}
# endif /* CONFIG_PPC_DCR */
/*
* For MMIO , get the physical address
*/
reg = of_get_property ( node , " reg " , NULL ) ;
if ( reg ) {
2012-07-26 03:34:37 +04:00
if ( of_can_translate_address ( node ) ) {
addr = of_translate_address ( node , reg ) ;
} else {
addrp = of_get_address ( node , 0 , NULL , NULL ) ;
if ( addrp )
addr = of_read_number ( addrp , 1 ) ;
else
addr = OF_BAD_ADDR ;
}
2010-06-08 17:48:14 +04:00
if ( addr ! = OF_BAD_ADDR ) {
dev_set_name ( dev , " %llx.%s " ,
( unsigned long long ) addr , node - > name ) ;
return ;
}
}
/*
* No BusID , use the node name and add a globally incremented
* counter ( and pray . . . )
*/
magic = atomic_add_return ( 1 , & bus_no_reg_magic ) ;
dev_set_name ( dev , " %s.%d " , node - > name , magic - 1 ) ;
}
/**
* 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 .
*/
2010-07-22 23:59:23 +04:00
struct platform_device * of_device_alloc ( struct device_node * np ,
2010-06-08 17:48:14 +04:00
const char * bus_id ,
struct device * parent )
{
2010-07-22 23:59:23 +04:00
struct platform_device * dev ;
2010-10-11 07:35:05 +04:00
int rc , i , num_reg = 0 , num_irq ;
2010-06-08 17:48:15 +04:00
struct resource * res , temp_res ;
2010-10-20 21:45:13 +04:00
dev = platform_device_alloc ( " " , - 1 ) ;
if ( ! dev )
return NULL ;
/* count the io and irq resources */
2012-07-26 03:34:37 +04:00
if ( of_can_translate_address ( np ) )
while ( of_address_to_resource ( np , num_reg , & temp_res ) = = 0 )
num_reg + + ;
2010-10-11 07:35:05 +04:00
num_irq = of_irq_count ( np ) ;
2010-06-08 17:48:15 +04:00
/* Populate the resource table */
if ( num_irq | | num_reg ) {
2010-10-20 21:45:13 +04:00
res = kzalloc ( sizeof ( * res ) * ( num_irq + num_reg ) , GFP_KERNEL ) ;
if ( ! res ) {
platform_device_put ( dev ) ;
return NULL ;
}
2010-06-08 17:48:15 +04:00
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 ) ;
}
2010-10-11 07:35:05 +04:00
WARN_ON ( of_irq_to_resource_table ( np , res , num_irq ) ! = num_irq ) ;
2010-06-08 17:48:15 +04:00
}
2010-06-08 17:48:14 +04:00
dev - > dev . of_node = of_node_get ( np ) ;
2011-07-08 09:17:27 +04:00
# if defined(CONFIG_MICROBLAZE)
2010-06-08 17:48:14 +04:00
dev - > dev . dma_mask = & dev - > archdata . dma_mask ;
2010-06-08 17:48:26 +04:00
# endif
2010-06-08 17:48:14 +04:00
dev - > dev . parent = parent ;
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 ) ;
2010-06-08 17:48:13 +04:00
/**
2011-06-21 20:59:35 +04:00
* of_platform_device_create_pdata - Alloc , initialize and register an of_device
2010-06-08 17:48:13 +04:00
* @ np : pointer to node to create device for
* @ bus_id : name to assign device
2011-06-21 20:59:35 +04:00
* @ platform_data : pointer to populate platform_data pointer with
2010-06-08 17:48:13 +04:00
* @ parent : Linux device model parent device .
2011-01-04 01:51:11 +03:00
*
* Returns pointer to created platform device , or NULL if a device was not
* registered . Unavailable devices will not get registered .
2010-06-08 17:48:13 +04:00
*/
2013-07-01 23:26:52 +04:00
static struct platform_device * of_platform_device_create_pdata (
2011-06-21 20:59:35 +04:00
struct device_node * np ,
const char * bus_id ,
void * platform_data ,
struct device * parent )
2010-06-08 17:48:13 +04:00
{
2010-07-22 23:59:23 +04:00
struct platform_device * dev ;
2010-06-08 17:48:13 +04:00
2011-01-04 01:51:11 +03:00
if ( ! of_device_is_available ( np ) )
return NULL ;
2010-06-08 17:48:13 +04:00
dev = of_device_alloc ( np , bus_id , parent ) ;
if ( ! dev )
return NULL ;
2011-07-08 09:17:27 +04:00
# if defined(CONFIG_MICROBLAZE)
2010-06-08 17:48:13 +04:00
dev - > archdata . dma_mask = 0xffffffffUL ;
2010-06-08 17:48:26 +04:00
# endif
2010-06-08 17:48:13 +04:00
dev - > dev . coherent_dma_mask = DMA_BIT_MASK ( 32 ) ;
2013-10-30 08:36:46 +04:00
if ( ! dev - > dev . dma_mask )
dev - > dev . dma_mask = & dev - > dev . coherent_dma_mask ;
2010-06-08 17:48:21 +04:00
dev - > dev . bus = & platform_bus_type ;
2011-06-21 20:59:35 +04:00
dev - > dev . platform_data = platform_data ;
2010-06-08 17:48:13 +04:00
/* We do not fill the DMA ops for platform devices by default.
* This is currently the responsibility of the platform code
* to do such , possibly using a device notifier
*/
2010-10-20 21:45:13 +04:00
if ( of_device_add ( dev ) ! = 0 ) {
platform_device_put ( dev ) ;
2010-06-08 17:48:13 +04:00
return NULL ;
}
return dev ;
}
2011-06-21 20:59:35 +04:00
/**
* 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 ) ;
}
2010-06-08 17:48:13 +04:00
EXPORT_SYMBOL ( of_platform_device_create ) ;
2011-06-21 20:59:34 +04:00
# 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 ;
pr_debug ( " Creating amba device %s \n " , node - > full_name ) ;
if ( ! of_device_is_available ( node ) )
return NULL ;
2011-12-18 15:45:17 +04:00
dev = amba_device_alloc ( NULL , 0 , 0 ) ;
2013-08-30 15:17:29 +04:00
if ( ! dev ) {
pr_err ( " %s(): amba_device_alloc() failed for %s \n " ,
__func__ , node - > full_name ) ;
2011-06-21 20:59:34 +04:00
return NULL ;
2013-08-30 15:17:29 +04:00
}
2011-06-21 20:59:34 +04:00
/* setup generic device info */
dev - > dev . coherent_dma_mask = ~ 0 ;
dev - > dev . of_node = of_node_get ( node ) ;
dev - > dev . parent = parent ;
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 ) ;
/* setup amba-specific device info */
dev - > dma_mask = ~ 0 ;
/* 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 ) ;
2013-08-30 15:17:29 +04:00
if ( ret ) {
pr_err ( " %s(): of_address_to_resource() failed (%d) for %s \n " ,
__func__ , ret , node - > full_name ) ;
2011-06-21 20:59:34 +04:00
goto err_free ;
2013-08-30 15:17:29 +04:00
}
2011-06-21 20:59:34 +04:00
2011-12-18 15:45:17 +04:00
ret = amba_device_add ( dev , & iomem_resource ) ;
2013-08-30 15:17:29 +04:00
if ( ret ) {
pr_err ( " %s(): amba_device_add() failed (%d) for %s \n " ,
__func__ , ret , node - > full_name ) ;
2011-06-21 20:59:34 +04:00
goto err_free ;
2013-08-30 15:17:29 +04:00
}
2011-06-21 20:59:34 +04:00
return dev ;
err_free :
2011-12-18 15:45:17 +04:00
amba_device_put ( dev ) ;
2011-06-21 20:59:34 +04:00
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 */
2011-06-21 20:59:35 +04:00
/**
* 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 ;
2011-11-03 09:07:29 +04:00
if ( ! lookup )
return NULL ;
2011-12-12 20:26:00 +04:00
for ( ; lookup - > compatible ! = NULL ; lookup + + ) {
2011-11-03 09:07:29 +04:00
if ( ! of_device_is_compatible ( np , lookup - > compatible ) )
continue ;
2012-07-05 18:15:36 +04:00
if ( ! of_address_to_resource ( np , 0 , & res ) )
if ( res . start ! = lookup - > phys_addr )
continue ;
2011-11-03 09:07:29 +04:00
pr_debug ( " %s: devname=%s \n " , np - > full_name , lookup - > name ) ;
return lookup ;
2011-06-21 20:59:35 +04:00
}
2011-11-03 09:07:29 +04:00
2011-06-21 20:59:35 +04:00
return NULL ;
}
2010-06-08 17:48:13 +04:00
/**
2011-03-18 19:21:28 +03:00
* of_platform_bus_create ( ) - Create a device for a node and its children .
2010-06-08 17:48:13 +04:00
* @ bus : device node of the bus to instantiate
2011-03-18 19:21:29 +03:00
* @ matches : match table for bus nodes
2011-11-03 09:07:29 +04:00
* @ lookup : auxdata table for matching id and platform_data with device nodes
2011-03-18 19:21:28 +03:00
* @ parent : parent for new device , or NULL for top level .
2011-11-03 09:07:29 +04:00
* @ strict : require compatible property
2011-03-18 19:21:28 +03:00
*
* Creates a platform_device for the provided device_node , and optionally
* recursively create devices for all the child nodes .
2010-06-08 17:48:13 +04:00
*/
2011-03-18 19:21:28 +03:00
static int of_platform_bus_create ( struct device_node * bus ,
2010-06-08 17:48:13 +04:00
const struct of_device_id * matches ,
2011-06-21 20:59:35 +04:00
const struct of_dev_auxdata * lookup ,
2011-06-21 20:59:34 +04:00
struct device * parent , bool strict )
2010-06-08 17:48:13 +04:00
{
2011-06-21 20:59:35 +04:00
const struct of_dev_auxdata * auxdata ;
2010-06-08 17:48:13 +04:00
struct device_node * child ;
2010-07-22 23:59:23 +04:00
struct platform_device * dev ;
2011-06-21 20:59:35 +04:00
const char * bus_id = NULL ;
void * platform_data = NULL ;
2010-06-08 17:48:13 +04:00
int rc = 0 ;
2011-06-21 20:59:34 +04:00
/* Make sure it has a compatible property */
if ( strict & & ( ! of_get_property ( bus , " compatible " , NULL ) ) ) {
pr_debug ( " %s() - skipping %s, no compatible prop \n " ,
__func__ , bus - > full_name ) ;
return 0 ;
}
2011-06-21 20:59:35 +04:00
auxdata = of_dev_lookup ( lookup , bus ) ;
if ( auxdata ) {
bus_id = auxdata - > name ;
platform_data = auxdata - > platform_data ;
}
2011-06-21 20:59:34 +04:00
if ( of_device_is_compatible ( bus , " arm,primecell " ) ) {
2013-08-30 15:17:29 +04:00
/*
* Don ' t return an error here to keep compatibility with older
* device tree files .
*/
2011-06-21 20:59:35 +04:00
of_amba_device_create ( bus , bus_id , platform_data , parent ) ;
2011-06-21 20:59:34 +04:00
return 0 ;
}
2011-06-21 20:59:35 +04:00
dev = of_platform_device_create_pdata ( bus , bus_id , platform_data , parent ) ;
2011-03-18 19:21:28 +03:00
if ( ! dev | | ! of_match_node ( matches , bus ) )
return 0 ;
2010-06-08 17:48:13 +04:00
for_each_child_of_node ( bus , child ) {
pr_debug ( " create child: %s \n " , child - > full_name ) ;
2011-06-21 20:59:35 +04:00
rc = of_platform_bus_create ( child , matches , lookup , & dev - > dev , strict ) ;
2010-06-08 17:48:13 +04:00
if ( rc ) {
of_node_put ( child ) ;
break ;
}
}
return rc ;
}
/**
2011-03-18 19:21:28 +03:00
* of_platform_bus_probe ( ) - Probe the device - tree for platform buses
2010-06-08 17:48:13 +04:00
* @ root : parent of the first level to probe or NULL for the root of the tree
2011-03-18 19:21:29 +03:00
* @ matches : match table for bus nodes
2010-06-08 17:48:13 +04:00
* @ 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 ;
int rc = 0 ;
2011-03-18 19:21:29 +03:00
root = root ? of_node_get ( root ) : of_find_node_by_path ( " / " ) ;
if ( ! root )
2010-06-08 17:48:25 +04:00
return - EINVAL ;
2010-06-08 17:48:13 +04:00
pr_debug ( " of_platform_bus_probe() \n " ) ;
pr_debug ( " starting at: %s \n " , root - > full_name ) ;
2011-03-18 19:21:29 +03:00
/* Do a self check of bus type, if there's a match, create children */
2010-06-08 17:48:13 +04:00
if ( of_match_node ( matches , root ) ) {
2011-06-21 20:59:35 +04:00
rc = of_platform_bus_create ( root , matches , NULL , parent , false ) ;
2011-03-18 19:21:28 +03:00
} else for_each_child_of_node ( root , child ) {
2010-06-08 17:48:13 +04:00
if ( ! of_match_node ( matches , child ) )
continue ;
2011-06-21 20:59:35 +04:00
rc = of_platform_bus_create ( child , matches , NULL , parent , false ) ;
2011-03-18 19:21:28 +03:00
if ( rc )
2010-06-08 17:48:13 +04:00
break ;
}
2011-03-18 19:21:28 +03:00
2010-06-08 17:48:13 +04:00
of_node_put ( root ) ;
return rc ;
}
EXPORT_SYMBOL ( of_platform_bus_probe ) ;
2011-06-21 20:59:34 +04:00
/**
* 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
2012-11-23 20:25:08 +04:00
* @ lookup : auxdata table for matching id and platform_data with device nodes
2011-06-21 20:59:34 +04:00
* @ 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 ,
2011-06-21 20:59:35 +04:00
const struct of_dev_auxdata * lookup ,
2011-06-21 20:59:34 +04:00
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 ;
for_each_child_of_node ( root , child ) {
2011-06-21 20:59:35 +04:00
rc = of_platform_bus_create ( child , matches , lookup , parent , true ) ;
2011-06-21 20:59:34 +04:00
if ( rc )
break ;
}
of_node_put ( root ) ;
return rc ;
}
2012-06-08 03:57:36 +04:00
EXPORT_SYMBOL_GPL ( of_platform_populate ) ;
2012-02-25 01:58:34 +04:00
# endif /* CONFIG_OF_ADDRESS */