2011-08-25 17:34:01 +04:00
/*
* drivers / base / power / common . c - Common device power management code .
*
* Copyright ( C ) 2011 Rafael J . Wysocki < rjw @ sisk . pl > , Renesas Electronics Corp .
*
* This file is released under the GPLv2 .
*/
# include <linux/kernel.h>
2012-01-22 20:23:42 +04:00
# include <linux/device.h>
2011-09-29 02:23:03 +04:00
# include <linux/export.h>
2011-08-25 17:34:01 +04:00
# include <linux/slab.h>
2011-08-25 17:34:19 +04:00
# include <linux/pm_clock.h>
2014-09-19 22:27:37 +04:00
# include <linux/acpi.h>
# include <linux/pm_domain.h>
2011-08-25 17:34:01 +04:00
2016-01-07 18:46:14 +03:00
# include "power.h"
2011-08-25 17:34:01 +04:00
/**
* dev_pm_get_subsys_data - Create or refcount power . subsys_data for device .
* @ dev : Device to handle .
*
* If power . subsys_data is NULL , point it to a new object , otherwise increment
2015-01-29 20:39:04 +03:00
* its reference counter . Return 0 if new object has been created or refcount
* increased , otherwise negative error code .
2011-08-25 17:34:01 +04:00
*/
int dev_pm_get_subsys_data ( struct device * dev )
{
struct pm_subsys_data * psd ;
psd = kzalloc ( sizeof ( * psd ) , GFP_KERNEL ) ;
if ( ! psd )
return - ENOMEM ;
spin_lock_irq ( & dev - > power . lock ) ;
if ( dev - > power . subsys_data ) {
dev - > power . subsys_data - > refcount + + ;
} else {
spin_lock_init ( & psd - > lock ) ;
psd - > refcount = 1 ;
dev - > power . subsys_data = psd ;
pm_clk_init ( dev ) ;
psd = NULL ;
}
spin_unlock_irq ( & dev - > power . lock ) ;
/* kfree() verifies that its argument is nonzero. */
kfree ( psd ) ;
2012-08-07 15:50:14 +04:00
return 0 ;
2011-08-25 17:34:01 +04:00
}
EXPORT_SYMBOL_GPL ( dev_pm_get_subsys_data ) ;
/**
* dev_pm_put_subsys_data - Drop reference to power . subsys_data .
* @ dev : Device to handle .
*
* If the reference counter of power . subsys_data is zero after dropping the
2015-01-29 20:39:05 +03:00
* reference , power . subsys_data is removed .
2011-08-25 17:34:01 +04:00
*/
2015-01-29 20:39:05 +03:00
void dev_pm_put_subsys_data ( struct device * dev )
2011-08-25 17:34:01 +04:00
{
struct pm_subsys_data * psd ;
spin_lock_irq ( & dev - > power . lock ) ;
psd = dev_to_psd ( dev ) ;
2013-05-08 03:14:32 +04:00
if ( ! psd )
2011-08-25 17:34:01 +04:00
goto out ;
2015-01-29 20:39:05 +03:00
if ( - - psd - > refcount = = 0 )
2011-08-25 17:34:01 +04:00
dev - > power . subsys_data = NULL ;
2015-01-29 20:39:05 +03:00
else
2013-05-08 03:14:32 +04:00
psd = NULL ;
2011-08-25 17:34:01 +04:00
out :
spin_unlock_irq ( & dev - > power . lock ) ;
2013-05-08 03:14:32 +04:00
kfree ( psd ) ;
2011-08-25 17:34:01 +04:00
}
EXPORT_SYMBOL_GPL ( dev_pm_put_subsys_data ) ;
2014-09-19 22:27:37 +04:00
/**
* dev_pm_domain_attach - Attach a device to its PM domain .
* @ dev : Device to attach .
* @ power_on : Used to indicate whether we should power on the device .
*
* The @ dev may only be attached to a single PM domain . By iterating through
* the available alternatives we try to find a valid PM domain for the device .
* As attachment succeeds , the - > detach ( ) callback in the struct dev_pm_domain
* should be assigned by the corresponding attach function .
*
* This function should typically be invoked from subsystem level code during
* the probe phase . Especially for those that holds devices which requires
* power management through PM domains .
*
* Callers must ensure proper synchronization of this function with power
* management callbacks .
*
* Returns 0 on successfully attached PM domain or negative error code .
*/
int dev_pm_domain_attach ( struct device * dev , bool power_on )
{
int ret ;
ret = acpi_dev_pm_attach ( dev , power_on ) ;
if ( ret )
ret = genpd_dev_pm_attach ( dev ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( dev_pm_domain_attach ) ;
/**
* dev_pm_domain_detach - Detach a device from its PM domain .
2015-12-29 13:03:21 +03:00
* @ dev : Device to detach .
2014-09-19 22:27:37 +04:00
* @ power_off : Used to indicate whether we should power off the device .
*
* This functions will reverse the actions from dev_pm_domain_attach ( ) and thus
* try to detach the @ dev from its PM domain . Typically it should be invoked
* from subsystem level code during the remove phase .
*
* Callers must ensure proper synchronization of this function with power
* management callbacks .
*/
void dev_pm_domain_detach ( struct device * dev , bool power_off )
{
if ( dev - > pm_domain & & dev - > pm_domain - > detach )
dev - > pm_domain - > detach ( dev , power_off ) ;
}
EXPORT_SYMBOL_GPL ( dev_pm_domain_detach ) ;
2016-01-07 18:46:13 +03:00
/**
* dev_pm_domain_set - Set PM domain of a device .
* @ dev : Device whose PM domain is to be set .
* @ pd : PM domain to be set , or NULL .
*
* Sets the PM domain the device belongs to . The PM domain of a device needs
* to be set before its probe finishes ( it ' s bound to a driver ) .
*
* This function must be called with the device lock held .
*/
void dev_pm_domain_set ( struct device * dev , struct dev_pm_domain * pd )
{
if ( dev - > pm_domain = = pd )
return ;
2016-01-30 14:54:29 +03:00
WARN ( pd & & device_is_bound ( dev ) ,
2016-01-07 18:46:13 +03:00
" PM domains can only be changed for unbound devices \n " ) ;
dev - > pm_domain = pd ;
2016-01-07 18:46:14 +03:00
device_pm_check_callbacks ( dev ) ;
2016-01-07 18:46:13 +03:00
}
EXPORT_SYMBOL_GPL ( dev_pm_domain_set ) ;