2009-03-27 16:25:12 +03:00
/*
* Copyright ( C ) 2006 Benjamin Herrenschmidt , IBM Corp .
* < benh @ kernel . crashing . org >
* and Arnd Bergmann , IBM Corp .
*
* 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 .
*
*/
# undef DEBUG
# include <linux/string.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
# include <linux/mod_devicetable.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/of_platform.h>
# include <linux/errno.h>
# include <linux/topology.h>
# include <asm/atomic.h>
struct bus_type of_platform_bus_type = {
. uevent = of_device_uevent ,
} ;
EXPORT_SYMBOL ( of_platform_bus_type ) ;
static int __init of_bus_driver_init ( void )
{
return of_bus_type_init ( & of_platform_bus_type , " of_platform " ) ;
}
postcore_initcall ( of_bus_driver_init ) ;
struct of_device * of_platform_device_create ( struct device_node * np ,
const char * bus_id ,
struct device * parent )
{
struct of_device * dev ;
dev = of_device_alloc ( np , bus_id , parent ) ;
if ( ! dev )
return NULL ;
dev - > dma_mask = 0xffffffffUL ;
dev - > dev . bus = & of_platform_bus_type ;
/* 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
*/
if ( of_device_register ( dev ) ! = 0 ) {
of_device_free ( dev ) ;
return NULL ;
}
return dev ;
}
EXPORT_SYMBOL ( of_platform_device_create ) ;
/**
* of_platform_bus_create - Create an OF device for a bus node and all its
* children . Optionally recursively instanciate matching busses .
* @ bus : device node of the bus to instanciate
* @ matches : match table , NULL to use the default , OF_NO_DEEP_PROBE to
* disallow recursive creation of child busses
*/
static int of_platform_bus_create ( const struct device_node * bus ,
const struct of_device_id * matches ,
struct device * parent )
{
struct device_node * child ;
struct of_device * dev ;
int rc = 0 ;
for_each_child_of_node ( bus , child ) {
pr_debug ( " create child: %s \n " , child - > full_name ) ;
dev = of_platform_device_create ( child , NULL , parent ) ;
if ( dev = = NULL )
rc = - ENOMEM ;
else if ( ! of_match_node ( matches , child ) )
continue ;
if ( rc = = 0 ) {
pr_debug ( " and sub busses \n " ) ;
rc = of_platform_bus_create ( child , matches , & dev - > dev ) ;
}
if ( rc ) {
of_node_put ( child ) ;
break ;
}
}
return rc ;
}
/**
* of_platform_bus_probe - Probe the device - tree for platform busses
* @ root : parent of the first level to probe or NULL for the root of the tree
* @ matches : match table , NULL to use the default
* @ parent : parent to hook devices from , NULL for toplevel
*
* Note that children of the provided root are not instanciated 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 ;
struct of_device * dev ;
int rc = 0 ;
if ( matches = = NULL )
matches = of_default_bus_ids ;
if ( matches = = OF_NO_DEEP_PROBE )
return - EINVAL ;
if ( root = = NULL )
root = of_find_node_by_path ( " / " ) ;
else
of_node_get ( root ) ;
pr_debug ( " of_platform_bus_probe() \n " ) ;
pr_debug ( " starting at: %s \n " , root - > full_name ) ;
/* Do a self check of bus type, if there's a match, create
* children
*/
if ( of_match_node ( matches , root ) ) {
pr_debug ( " root match, create all sub devices \n " ) ;
dev = of_platform_device_create ( root , NULL , parent ) ;
if ( dev = = NULL ) {
rc = - ENOMEM ;
goto bail ;
}
pr_debug ( " create all sub busses \n " ) ;
rc = of_platform_bus_create ( root , matches , & dev - > dev ) ;
goto bail ;
}
for_each_child_of_node ( root , child ) {
if ( ! of_match_node ( matches , child ) )
continue ;
pr_debug ( " match: %s \n " , child - > full_name ) ;
dev = of_platform_device_create ( child , NULL , parent ) ;
if ( dev = = NULL )
rc = - ENOMEM ;
else
rc = of_platform_bus_create ( child , matches , & dev - > dev ) ;
if ( rc ) {
of_node_put ( child ) ;
break ;
}
}
bail :
of_node_put ( root ) ;
return rc ;
}
EXPORT_SYMBOL ( of_platform_bus_probe ) ;
static int of_dev_node_match ( struct device * dev , void * data )
{
return to_of_device ( dev ) - > node = = data ;
}
struct of_device * of_find_device_by_node ( struct device_node * np )
{
struct device * dev ;
dev = bus_find_device ( & of_platform_bus_type ,
NULL , np , of_dev_node_match ) ;
if ( dev )
return to_of_device ( dev ) ;
return NULL ;
}
EXPORT_SYMBOL ( of_find_device_by_node ) ;
static int of_dev_phandle_match ( struct device * dev , void * data )
{
phandle * ph = data ;
2010-01-29 00:06:53 +03:00
return to_of_device ( dev ) - > node - > phandle = = * ph ;
2009-03-27 16:25:12 +03:00
}
struct of_device * of_find_device_by_phandle ( phandle ph )
{
struct device * dev ;
dev = bus_find_device ( & of_platform_bus_type ,
NULL , & ph , of_dev_phandle_match ) ;
if ( dev )
return to_of_device ( dev ) ;
return NULL ;
}
EXPORT_SYMBOL ( of_find_device_by_phandle ) ;