2007-05-03 02:38:57 +10: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-17 21:17:42 -07:00
# include <linux/module.h>
2007-05-03 02:38:57 +10:00
# include <linux/device.h>
# include <linux/of_device.h>
# include <linux/of_platform.h>
2008-04-24 23:16:00 +10:00
extern struct device_attribute of_platform_device_attrs [ ] ;
2007-05-03 02:38:57 +10:00
static int of_platform_bus_match ( struct device * dev , struct device_driver * drv )
{
struct of_device * of_dev = to_of_device ( dev ) ;
struct of_platform_driver * of_drv = to_of_platform_driver ( drv ) ;
const struct of_device_id * matches = of_drv - > match_table ;
if ( ! matches )
return 0 ;
return of_match_device ( matches , of_dev ) ! = NULL ;
}
static int of_platform_device_probe ( struct device * dev )
{
int error = - ENODEV ;
struct of_platform_driver * drv ;
struct of_device * of_dev ;
const struct of_device_id * match ;
drv = to_of_platform_driver ( dev - > driver ) ;
of_dev = to_of_device ( dev ) ;
if ( ! drv - > probe )
return error ;
of_dev_get ( of_dev ) ;
match = of_match_device ( drv - > match_table , of_dev ) ;
if ( match )
error = drv - > probe ( of_dev , match ) ;
if ( error )
of_dev_put ( of_dev ) ;
return error ;
}
static int of_platform_device_remove ( struct device * dev )
{
struct of_device * of_dev = to_of_device ( dev ) ;
struct of_platform_driver * drv = to_of_platform_driver ( dev - > driver ) ;
if ( dev - > driver & & drv - > remove )
drv - > remove ( of_dev ) ;
return 0 ;
}
2009-10-12 05:50:41 +00:00
static void of_platform_device_shutdown ( struct device * dev )
2007-05-03 02:38:57 +10:00
{
struct of_device * of_dev = to_of_device ( dev ) ;
struct of_platform_driver * drv = to_of_platform_driver ( dev - > driver ) ;
2009-10-12 05:50:41 +00:00
if ( dev - > driver & & drv - > shutdown )
drv - > shutdown ( of_dev ) ;
2007-05-03 02:38:57 +10:00
}
2009-10-12 05:50:41 +00:00
# ifdef CONFIG_PM_SLEEP
static int of_platform_legacy_suspend ( struct device * dev , pm_message_t mesg )
2007-05-03 02:38:57 +10:00
{
struct of_device * of_dev = to_of_device ( dev ) ;
struct of_platform_driver * drv = to_of_platform_driver ( dev - > driver ) ;
2009-10-12 05:50:41 +00:00
int ret = 0 ;
2007-05-03 02:38:57 +10:00
2009-10-12 05:50:41 +00:00
if ( dev - > driver & & drv - > suspend )
ret = drv - > suspend ( of_dev , mesg ) ;
return ret ;
2007-05-03 02:38:57 +10:00
}
2009-10-12 05:50:41 +00:00
static int of_platform_legacy_resume ( struct device * dev )
2008-01-25 16:59:13 +11:00
{
struct of_device * of_dev = to_of_device ( dev ) ;
struct of_platform_driver * drv = to_of_platform_driver ( dev - > driver ) ;
2009-10-12 05:50:41 +00:00
int ret = 0 ;
2008-01-25 16:59:13 +11:00
2009-10-12 05:50:41 +00:00
if ( dev - > driver & & drv - > resume )
ret = drv - > resume ( of_dev ) ;
return ret ;
}
static int of_platform_pm_prepare ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( drv & & drv - > pm & & drv - > pm - > prepare )
ret = drv - > pm - > prepare ( dev ) ;
return ret ;
}
static void of_platform_pm_complete ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
if ( drv & & drv - > pm & & drv - > pm - > complete )
drv - > pm - > complete ( dev ) ;
}
# ifdef CONFIG_SUSPEND
static int of_platform_pm_suspend ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > suspend )
ret = drv - > pm - > suspend ( dev ) ;
} else {
ret = of_platform_legacy_suspend ( dev , PMSG_SUSPEND ) ;
}
return ret ;
2008-01-25 16:59:13 +11:00
}
2009-10-12 05:50:41 +00:00
static int of_platform_pm_suspend_noirq ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > suspend_noirq )
ret = drv - > pm - > suspend_noirq ( dev ) ;
}
return ret ;
}
static int of_platform_pm_resume ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > resume )
ret = drv - > pm - > resume ( dev ) ;
} else {
ret = of_platform_legacy_resume ( dev ) ;
}
return ret ;
}
static int of_platform_pm_resume_noirq ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > resume_noirq )
ret = drv - > pm - > resume_noirq ( dev ) ;
}
return ret ;
}
# else /* !CONFIG_SUSPEND */
# define of_platform_pm_suspend NULL
# define of_platform_pm_resume NULL
# define of_platform_pm_suspend_noirq NULL
# define of_platform_pm_resume_noirq NULL
# endif /* !CONFIG_SUSPEND */
# ifdef CONFIG_HIBERNATION
static int of_platform_pm_freeze ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > freeze )
ret = drv - > pm - > freeze ( dev ) ;
} else {
ret = of_platform_legacy_suspend ( dev , PMSG_FREEZE ) ;
}
return ret ;
}
static int of_platform_pm_freeze_noirq ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > freeze_noirq )
ret = drv - > pm - > freeze_noirq ( dev ) ;
}
return ret ;
}
static int of_platform_pm_thaw ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > thaw )
ret = drv - > pm - > thaw ( dev ) ;
} else {
ret = of_platform_legacy_resume ( dev ) ;
}
return ret ;
}
static int of_platform_pm_thaw_noirq ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > thaw_noirq )
ret = drv - > pm - > thaw_noirq ( dev ) ;
}
return ret ;
}
static int of_platform_pm_poweroff ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > poweroff )
ret = drv - > pm - > poweroff ( dev ) ;
} else {
ret = of_platform_legacy_suspend ( dev , PMSG_HIBERNATE ) ;
}
return ret ;
}
static int of_platform_pm_poweroff_noirq ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > poweroff_noirq )
ret = drv - > pm - > poweroff_noirq ( dev ) ;
}
return ret ;
}
static int of_platform_pm_restore ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > restore )
ret = drv - > pm - > restore ( dev ) ;
} else {
ret = of_platform_legacy_resume ( dev ) ;
}
return ret ;
}
static int of_platform_pm_restore_noirq ( struct device * dev )
{
struct device_driver * drv = dev - > driver ;
int ret = 0 ;
if ( ! drv )
return 0 ;
if ( drv - > pm ) {
if ( drv - > pm - > restore_noirq )
ret = drv - > pm - > restore_noirq ( dev ) ;
}
return ret ;
}
# else /* !CONFIG_HIBERNATION */
# define of_platform_pm_freeze NULL
# define of_platform_pm_thaw NULL
# define of_platform_pm_poweroff NULL
# define of_platform_pm_restore NULL
# define of_platform_pm_freeze_noirq NULL
# define of_platform_pm_thaw_noirq NULL
# define of_platform_pm_poweroff_noirq NULL
# define of_platform_pm_restore_noirq NULL
# endif /* !CONFIG_HIBERNATION */
static struct dev_pm_ops of_platform_dev_pm_ops = {
. prepare = of_platform_pm_prepare ,
. complete = of_platform_pm_complete ,
. suspend = of_platform_pm_suspend ,
. resume = of_platform_pm_resume ,
. freeze = of_platform_pm_freeze ,
. thaw = of_platform_pm_thaw ,
. poweroff = of_platform_pm_poweroff ,
. restore = of_platform_pm_restore ,
. suspend_noirq = of_platform_pm_suspend_noirq ,
. resume_noirq = of_platform_pm_resume_noirq ,
. freeze_noirq = of_platform_pm_freeze_noirq ,
. thaw_noirq = of_platform_pm_thaw_noirq ,
. poweroff_noirq = of_platform_pm_poweroff_noirq ,
. restore_noirq = of_platform_pm_restore_noirq ,
} ;
# define OF_PLATFORM_PM_OPS_PTR (&of_platform_dev_pm_ops)
# else /* !CONFIG_PM_SLEEP */
# define OF_PLATFORM_PM_OPS_PTR NULL
# endif /* !CONFIG_PM_SLEEP */
2007-05-03 02:38:57 +10:00
int of_bus_type_init ( struct bus_type * bus , const char * name )
{
bus - > name = name ;
bus - > match = of_platform_bus_match ;
bus - > probe = of_platform_device_probe ;
bus - > remove = of_platform_device_remove ;
2008-01-25 16:59:13 +11:00
bus - > shutdown = of_platform_device_shutdown ;
2008-04-24 23:16:00 +10:00
bus - > dev_attrs = of_platform_device_attrs ;
2009-10-12 05:50:41 +00:00
bus - > pm = OF_PLATFORM_PM_OPS_PTR ;
2007-05-03 02:38:57 +10:00
return bus_register ( bus ) ;
}
2007-10-17 21:17:42 -07:00
int of_register_driver ( struct of_platform_driver * drv , struct bus_type * bus )
{
/* initialize common driver fields */
if ( ! drv - > driver . name )
drv - > driver . name = drv - > name ;
if ( ! drv - > driver . owner )
drv - > driver . owner = drv - > owner ;
drv - > driver . bus = bus ;
/* register with core */
return driver_register ( & drv - > driver ) ;
}
EXPORT_SYMBOL ( of_register_driver ) ;
void of_unregister_driver ( struct of_platform_driver * drv )
{
driver_unregister ( & drv - > driver ) ;
}
EXPORT_SYMBOL ( of_unregister_driver ) ;