2007-05-04 00:27:45 +04:00
/*
* Universal power supply monitor class
*
* Copyright © 2007 Anton Vorontsov < cbou @ mail . ru >
* Copyright © 2004 Szabolcs Gyurko
* Copyright © 2003 Ian Molton < spyro @ f2s . com >
*
* Modified : 2004 , Oct Szabolcs Gyurko
*
* You may use this code as per GPL version 2
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/init.h>
2010-05-18 23:49:51 +04:00
# include <linux/slab.h>
2007-05-04 00:27:45 +04:00
# include <linux/device.h>
2013-11-19 14:18:03 +04:00
# include <linux/notifier.h>
2007-05-04 00:27:45 +04:00
# include <linux/err.h>
# include <linux/power_supply.h>
2012-05-09 19:06:47 +04:00
# include <linux/thermal.h>
2007-05-04 00:27:45 +04:00
# include "power_supply.h"
2009-07-30 17:42:31 +04:00
/* exported for the APM Power driver, APM emulation */
2007-05-04 00:27:45 +04:00
struct class * power_supply_class ;
2009-07-30 17:42:31 +04:00
EXPORT_SYMBOL_GPL ( power_supply_class ) ;
2007-05-04 00:27:45 +04:00
2013-11-19 14:18:03 +04:00
ATOMIC_NOTIFIER_HEAD ( power_supply_notifier ) ;
EXPORT_SYMBOL_GPL ( power_supply_notifier ) ;
2010-05-18 23:49:51 +04:00
static struct device_type power_supply_dev_type ;
2015-05-19 10:13:02 +03:00
# define POWER_SUPPLY_DEFERRED_REGISTER_TIME msecs_to_jiffies(10)
2013-04-02 01:45:54 +04:00
static bool __power_supply_is_supplied_by ( struct power_supply * supplier ,
struct power_supply * supply )
{
int i ;
if ( ! supply - > supplied_from & & ! supplier - > supplied_to )
return false ;
/* Support both supplied_to and supplied_from modes */
if ( supply - > supplied_from ) {
2015-03-12 10:44:11 +03:00
if ( ! supplier - > desc - > name )
2013-04-02 01:45:54 +04:00
return false ;
for ( i = 0 ; i < supply - > num_supplies ; i + + )
2015-03-12 10:44:11 +03:00
if ( ! strcmp ( supplier - > desc - > name , supply - > supplied_from [ i ] ) )
2013-04-02 01:45:54 +04:00
return true ;
} else {
2015-03-12 10:44:11 +03:00
if ( ! supply - > desc - > name )
2013-04-02 01:45:54 +04:00
return false ;
for ( i = 0 ; i < supplier - > num_supplicants ; i + + )
2015-03-12 10:44:11 +03:00
if ( ! strcmp ( supplier - > supplied_to [ i ] , supply - > desc - > name ) )
2013-04-02 01:45:54 +04:00
return true ;
}
return false ;
}
2008-01-22 08:58:22 +03:00
static int __power_supply_changed_work ( struct device * dev , void * data )
{
2014-09-04 16:01:26 +04:00
struct power_supply * psy = data ;
2008-01-22 08:58:22 +03:00
struct power_supply * pst = dev_get_drvdata ( dev ) ;
2013-04-02 01:45:54 +04:00
if ( __power_supply_is_supplied_by ( psy , pst ) ) {
2015-03-12 10:44:11 +03:00
if ( pst - > desc - > external_power_changed )
pst - > desc - > external_power_changed ( pst ) ;
2013-04-02 01:45:54 +04:00
}
2008-01-22 08:58:22 +03:00
return 0 ;
}
2007-05-04 00:27:45 +04:00
static void power_supply_changed_work ( struct work_struct * work )
{
2013-08-03 00:38:02 +04:00
unsigned long flags ;
2007-05-04 00:27:45 +04:00
struct power_supply * psy = container_of ( work , struct power_supply ,
changed_work ) ;
2015-03-12 10:44:11 +03:00
dev_dbg ( & psy - > dev , " %s \n " , __func__ ) ;
2007-05-04 00:27:45 +04:00
2013-08-03 00:38:02 +04:00
spin_lock_irqsave ( & psy - > changed_lock , flags ) ;
2014-09-04 16:01:32 +04:00
/*
* Check ' changed ' here to avoid issues due to race between
* power_supply_changed ( ) and this routine . In worst case
* power_supply_changed ( ) can be called again just before we take above
* lock . During the first call of this routine we will mark ' changed ' as
* false and it will stay false for the next call as well .
*/
if ( likely ( psy - > changed ) ) {
2013-08-03 00:38:02 +04:00
psy - > changed = false ;
spin_unlock_irqrestore ( & psy - > changed_lock , flags ) ;
class_for_each_device ( power_supply_class , NULL , psy ,
__power_supply_changed_work ) ;
power_supply_update_leds ( psy ) ;
2013-11-19 14:18:03 +04:00
atomic_notifier_call_chain ( & power_supply_notifier ,
PSY_EVENT_PROP_CHANGED , psy ) ;
2015-03-12 10:44:11 +03:00
kobject_uevent ( & psy - > dev . kobj , KOBJ_CHANGE ) ;
2013-08-03 00:38:02 +04:00
spin_lock_irqsave ( & psy - > changed_lock , flags ) ;
}
2014-09-04 16:01:32 +04:00
2013-08-03 00:38:02 +04:00
/*
2014-09-04 16:01:32 +04:00
* Hold the wakeup_source until all events are processed .
* power_supply_changed ( ) might have called again and have set ' changed '
* to true .
2013-08-03 00:38:02 +04:00
*/
2014-09-04 16:01:32 +04:00
if ( likely ( ! psy - > changed ) )
2015-03-12 10:44:11 +03:00
pm_relax ( & psy - > dev ) ;
2013-08-03 00:38:02 +04:00
spin_unlock_irqrestore ( & psy - > changed_lock , flags ) ;
2007-05-04 00:27:45 +04:00
}
void power_supply_changed ( struct power_supply * psy )
{
2013-08-03 00:38:02 +04:00
unsigned long flags ;
2015-03-12 10:44:11 +03:00
dev_dbg ( & psy - > dev , " %s \n " , __func__ ) ;
2007-05-04 00:27:45 +04:00
2013-08-03 00:38:02 +04:00
spin_lock_irqsave ( & psy - > changed_lock , flags ) ;
psy - > changed = true ;
2015-03-12 10:44:11 +03:00
pm_stay_awake ( & psy - > dev ) ;
2013-08-03 00:38:02 +04:00
spin_unlock_irqrestore ( & psy - > changed_lock , flags ) ;
2007-05-04 00:27:45 +04:00
schedule_work ( & psy - > changed_work ) ;
}
2009-07-30 17:42:31 +04:00
EXPORT_SYMBOL_GPL ( power_supply_changed ) ;
2007-05-04 00:27:45 +04:00
2015-05-19 10:13:02 +03:00
/*
* Notify that power supply was registered after parent finished the probing .
*
* Often power supply is registered from driver ' s probe function . However
* calling power_supply_changed ( ) directly from power_supply_register ( )
* would lead to execution of get_property ( ) function provided by the driver
* too early - before the probe ends .
*
* Avoid that by waiting on parent ' s mutex .
*/
static void power_supply_deferred_register_work ( struct work_struct * work )
{
struct power_supply * psy = container_of ( work , struct power_supply ,
deferred_register_work . work ) ;
if ( psy - > dev . parent )
mutex_lock ( & psy - > dev . parent - > mutex ) ;
power_supply_changed ( psy ) ;
if ( psy - > dev . parent )
mutex_unlock ( & psy - > dev . parent - > mutex ) ;
}
2013-04-02 01:45:55 +04:00
# ifdef CONFIG_OF
# include <linux/of.h>
static int __power_supply_populate_supplied_from ( struct device * dev ,
void * data )
{
2014-09-04 16:01:26 +04:00
struct power_supply * psy = data ;
2013-04-02 01:45:55 +04:00
struct power_supply * epsy = dev_get_drvdata ( dev ) ;
struct device_node * np ;
int i = 0 ;
do {
np = of_parse_phandle ( psy - > of_node , " power-supplies " , i + + ) ;
if ( ! np )
2014-09-04 16:01:27 +04:00
break ;
2013-04-02 01:45:55 +04:00
if ( np = = epsy - > of_node ) {
2015-03-12 10:44:11 +03:00
dev_info ( & psy - > dev , " %s: Found supply : %s \n " ,
psy - > desc - > name , epsy - > desc - > name ) ;
psy - > supplied_from [ i - 1 ] = ( char * ) epsy - > desc - > name ;
2013-04-02 01:45:55 +04:00
psy - > num_supplies + + ;
2013-06-11 01:26:39 +04:00
of_node_put ( np ) ;
2013-04-02 01:45:55 +04:00
break ;
}
2013-06-11 01:26:39 +04:00
of_node_put ( np ) ;
2013-04-02 01:45:55 +04:00
} while ( np ) ;
return 0 ;
}
static int power_supply_populate_supplied_from ( struct power_supply * psy )
{
int error ;
error = class_for_each_device ( power_supply_class , NULL , psy ,
__power_supply_populate_supplied_from ) ;
2015-03-12 10:44:11 +03:00
dev_dbg ( & psy - > dev , " %s %d \n " , __func__ , error ) ;
2013-04-02 01:45:55 +04:00
return error ;
}
static int __power_supply_find_supply_from_node ( struct device * dev ,
void * data )
{
2014-09-04 16:01:26 +04:00
struct device_node * np = data ;
2013-04-02 01:45:55 +04:00
struct power_supply * epsy = dev_get_drvdata ( dev ) ;
2014-09-04 16:01:30 +04:00
/* returning non-zero breaks out of class_for_each_device loop */
2013-04-02 01:45:55 +04:00
if ( epsy - > of_node = = np )
2014-09-04 16:01:30 +04:00
return 1 ;
2013-04-02 01:45:55 +04:00
return 0 ;
}
static int power_supply_find_supply_from_node ( struct device_node * supply_node )
{
int error ;
/*
2014-09-04 16:01:30 +04:00
* class_for_each_device ( ) either returns its own errors or values
* returned by __power_supply_find_supply_from_node ( ) .
*
* __power_supply_find_supply_from_node ( ) will return 0 ( no match )
* or 1 ( match ) .
*
* We return 0 if class_for_each_device ( ) returned 1 , - EPROBE_DEFER if
* it returned 0 , or error as returned by it .
2013-04-02 01:45:55 +04:00
*/
error = class_for_each_device ( power_supply_class , NULL , supply_node ,
__power_supply_find_supply_from_node ) ;
2014-09-04 16:01:30 +04:00
return error ? ( error = = 1 ? 0 : error ) : - EPROBE_DEFER ;
2013-04-02 01:45:55 +04:00
}
static int power_supply_check_supplies ( struct power_supply * psy )
{
struct device_node * np ;
int cnt = 0 ;
/* If there is already a list honor it */
if ( psy - > supplied_from & & psy - > num_supplies > 0 )
return 0 ;
/* No device node found, nothing to do */
if ( ! psy - > of_node )
return 0 ;
do {
int ret ;
np = of_parse_phandle ( psy - > of_node , " power-supplies " , cnt + + ) ;
if ( ! np )
2014-09-04 16:01:27 +04:00
break ;
2013-04-02 01:45:55 +04:00
ret = power_supply_find_supply_from_node ( np ) ;
2014-09-04 16:01:28 +04:00
of_node_put ( np ) ;
2013-04-02 01:45:55 +04:00
if ( ret ) {
2015-03-12 10:44:11 +03:00
dev_dbg ( & psy - > dev , " Failed to find supply! \n " ) ;
2014-09-04 16:01:29 +04:00
return ret ;
2013-04-02 01:45:55 +04:00
}
} while ( np ) ;
2014-09-04 16:01:23 +04:00
/* Missing valid "power-supplies" entries */
if ( cnt = = 1 )
return 0 ;
2013-04-02 01:45:55 +04:00
/* All supplies found, allocate char ** array for filling */
2015-03-12 10:44:11 +03:00
psy - > supplied_from = devm_kzalloc ( & psy - > dev , sizeof ( psy - > supplied_from ) ,
2013-04-02 01:45:55 +04:00
GFP_KERNEL ) ;
if ( ! psy - > supplied_from ) {
2015-03-12 10:44:11 +03:00
dev_err ( & psy - > dev , " Couldn't allocate memory for supply list \n " ) ;
2013-04-02 01:45:55 +04:00
return - ENOMEM ;
}
2015-03-12 10:44:11 +03:00
* psy - > supplied_from = devm_kzalloc ( & psy - > dev ,
sizeof ( char * ) * ( cnt - 1 ) ,
2013-04-02 01:45:55 +04:00
GFP_KERNEL ) ;
if ( ! * psy - > supplied_from ) {
2015-03-12 10:44:11 +03:00
dev_err ( & psy - > dev , " Couldn't allocate memory for supply list \n " ) ;
2013-04-02 01:45:55 +04:00
return - ENOMEM ;
}
return power_supply_populate_supplied_from ( psy ) ;
}
# else
static inline int power_supply_check_supplies ( struct power_supply * psy )
{
return 0 ;
}
# endif
2008-01-22 08:58:22 +03:00
static int __power_supply_am_i_supplied ( struct device * dev , void * data )
2007-05-04 00:27:45 +04:00
{
union power_supply_propval ret = { 0 , } ;
2014-09-04 16:01:26 +04:00
struct power_supply * psy = data ;
2008-01-22 08:58:22 +03:00
struct power_supply * epsy = dev_get_drvdata ( dev ) ;
2013-04-02 01:45:54 +04:00
if ( __power_supply_is_supplied_by ( epsy , psy ) )
2015-03-12 10:44:11 +03:00
if ( ! epsy - > desc - > get_property ( epsy , POWER_SUPPLY_PROP_ONLINE ,
& ret ) )
2014-09-04 16:01:31 +04:00
return ret . intval ;
2013-04-02 01:45:54 +04:00
2008-01-22 08:58:22 +03:00
return 0 ;
}
int power_supply_am_i_supplied ( struct power_supply * psy )
{
int error ;
2008-05-23 01:21:08 +04:00
error = class_for_each_device ( power_supply_class , NULL , psy ,
2008-01-22 08:58:22 +03:00
__power_supply_am_i_supplied ) ;
2007-05-04 00:27:45 +04:00
2015-03-12 10:44:11 +03:00
dev_dbg ( & psy - > dev , " %s %d \n " , __func__ , error ) ;
2007-05-04 00:27:45 +04:00
2008-01-22 08:58:22 +03:00
return error ;
2007-05-04 00:27:45 +04:00
}
2009-07-30 17:42:31 +04:00
EXPORT_SYMBOL_GPL ( power_supply_am_i_supplied ) ;
2007-05-04 00:27:45 +04:00
2008-08-27 00:09:59 +04:00
static int __power_supply_is_system_supplied ( struct device * dev , void * data )
{
union power_supply_propval ret = { 0 , } ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
2011-12-11 01:53:36 +04:00
unsigned int * count = data ;
2008-08-27 00:09:59 +04:00
2011-12-11 01:53:36 +04:00
( * count ) + + ;
2015-03-12 10:44:11 +03:00
if ( psy - > desc - > type ! = POWER_SUPPLY_TYPE_BATTERY )
if ( ! psy - > desc - > get_property ( psy , POWER_SUPPLY_PROP_ONLINE ,
& ret ) )
2008-08-27 00:09:59 +04:00
return ret . intval ;
2014-09-04 16:01:31 +04:00
2008-08-27 00:09:59 +04:00
return 0 ;
}
int power_supply_is_system_supplied ( void )
{
int error ;
2011-12-11 01:53:36 +04:00
unsigned int count = 0 ;
2008-08-27 00:09:59 +04:00
2011-12-11 01:53:36 +04:00
error = class_for_each_device ( power_supply_class , NULL , & count ,
2008-08-27 00:09:59 +04:00
__power_supply_is_system_supplied ) ;
2011-12-11 01:53:36 +04:00
/*
* If no power class device was found at all , most probably we are
* running on a desktop system , so assume we are on mains power .
*/
if ( count = = 0 )
return 1 ;
2008-08-27 00:09:59 +04:00
return error ;
}
2009-07-30 17:42:31 +04:00
EXPORT_SYMBOL_GPL ( power_supply_is_system_supplied ) ;
2008-08-27 00:09:59 +04:00
2009-07-23 22:35:53 +04:00
int power_supply_set_battery_charged ( struct power_supply * psy )
{
2015-03-12 10:44:03 +03:00
if ( atomic_read ( & psy - > use_cnt ) > = 0 & &
2015-03-12 10:44:11 +03:00
psy - > desc - > type = = POWER_SUPPLY_TYPE_BATTERY & &
psy - > desc - > set_charged ) {
psy - > desc - > set_charged ( psy ) ;
2009-07-23 22:35:53 +04:00
return 0 ;
}
return - EINVAL ;
}
EXPORT_SYMBOL_GPL ( power_supply_set_battery_charged ) ;
2013-02-01 23:40:17 +04:00
static int power_supply_match_device_by_name ( struct device * dev , const void * data )
2009-07-23 22:35:53 +04:00
{
const char * name = data ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
2015-03-12 10:44:11 +03:00
return strcmp ( psy - > desc - > name , name ) = = 0 ;
2009-07-23 22:35:53 +04:00
}
2015-03-12 10:44:12 +03:00
/**
* power_supply_get_by_name ( ) - Search for a power supply and returns its ref
* @ name : Power supply name to fetch
*
* If power supply was found , it increases reference count for the
* internal power supply ' s device . The user should power_supply_put ( )
* after usage .
*
* Return : On success returns a reference to a power supply with
* matching name equals to @ name , a NULL otherwise .
*/
2013-02-01 23:40:17 +04:00
struct power_supply * power_supply_get_by_name ( const char * name )
2009-07-23 22:35:53 +04:00
{
2015-03-12 10:44:13 +03:00
struct power_supply * psy = NULL ;
2009-07-23 22:35:53 +04:00
struct device * dev = class_find_device ( power_supply_class , NULL , name ,
power_supply_match_device_by_name ) ;
2015-03-12 10:44:13 +03:00
if ( dev ) {
psy = dev_get_drvdata ( dev ) ;
atomic_inc ( & psy - > use_cnt ) ;
}
return psy ;
2009-07-23 22:35:53 +04:00
}
EXPORT_SYMBOL_GPL ( power_supply_get_by_name ) ;
2015-03-12 10:44:12 +03:00
/**
* power_supply_put ( ) - Drop reference obtained with power_supply_get_by_name
* @ psy : Reference to put
*
* The reference to power supply should be put before unregistering
* the power supply .
*/
void power_supply_put ( struct power_supply * psy )
{
might_sleep ( ) ;
2015-03-12 10:44:13 +03:00
atomic_dec ( & psy - > use_cnt ) ;
2015-03-12 10:44:12 +03:00
put_device ( & psy - > dev ) ;
}
EXPORT_SYMBOL_GPL ( power_supply_put ) ;
2013-11-24 20:49:29 +04:00
# ifdef CONFIG_OF
static int power_supply_match_device_node ( struct device * dev , const void * data )
{
return dev - > parent & & dev - > parent - > of_node = = data ;
}
2015-03-12 10:44:12 +03:00
/**
* power_supply_get_by_phandle ( ) - Search for a power supply and returns its ref
* @ np : Pointer to device node holding phandle property
* @ phandle_name : Name of property holding a power supply name
*
* If power supply was found , it increases reference count for the
* internal power supply ' s device . The user should power_supply_put ( )
* after usage .
*
* Return : On success returns a reference to a power supply with
* matching name equals to value under @ property , NULL or ERR_PTR otherwise .
*/
2013-11-24 20:49:29 +04:00
struct power_supply * power_supply_get_by_phandle ( struct device_node * np ,
const char * property )
{
struct device_node * power_supply_np ;
2015-03-12 10:44:13 +03:00
struct power_supply * psy = NULL ;
2013-11-24 20:49:29 +04:00
struct device * dev ;
power_supply_np = of_parse_phandle ( np , property , 0 ) ;
if ( ! power_supply_np )
return ERR_PTR ( - ENODEV ) ;
dev = class_find_device ( power_supply_class , NULL , power_supply_np ,
power_supply_match_device_node ) ;
of_node_put ( power_supply_np ) ;
2015-03-12 10:44:13 +03:00
if ( dev ) {
psy = dev_get_drvdata ( dev ) ;
atomic_inc ( & psy - > use_cnt ) ;
}
return psy ;
2013-11-24 20:49:29 +04:00
}
EXPORT_SYMBOL_GPL ( power_supply_get_by_phandle ) ;
2015-06-10 00:37:56 +03:00
static void devm_power_supply_put ( struct device * dev , void * res )
{
struct power_supply * * psy = res ;
power_supply_put ( * psy ) ;
}
/**
* devm_power_supply_get_by_phandle ( ) - Resource managed version of
* power_supply_get_by_phandle ( )
* @ dev : Pointer to device holding phandle property
* @ phandle_name : Name of property holding a power supply phandle
*
* Return : On success returns a reference to a power supply with
* matching name equals to value under @ property , NULL or ERR_PTR otherwise .
*/
struct power_supply * devm_power_supply_get_by_phandle ( struct device * dev ,
const char * property )
{
struct power_supply * * ptr , * psy ;
if ( ! dev - > of_node )
return ERR_PTR ( - ENODEV ) ;
ptr = devres_alloc ( devm_power_supply_put , sizeof ( * ptr ) , GFP_KERNEL ) ;
if ( ! ptr )
return ERR_PTR ( - ENOMEM ) ;
psy = power_supply_get_by_phandle ( dev - > of_node , property ) ;
if ( IS_ERR_OR_NULL ( psy ) ) {
devres_free ( ptr ) ;
} else {
* ptr = psy ;
devres_add ( dev , ptr ) ;
}
return psy ;
}
EXPORT_SYMBOL_GPL ( devm_power_supply_get_by_phandle ) ;
2013-11-24 20:49:29 +04:00
# endif /* CONFIG_OF */
2015-03-12 10:44:03 +03:00
int power_supply_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
2016-06-22 18:45:52 +03:00
if ( atomic_read ( & psy - > use_cnt ) < = 0 ) {
if ( ! psy - > initialized )
return - EAGAIN ;
2015-03-12 10:44:03 +03:00
return - ENODEV ;
2016-06-22 18:45:52 +03:00
}
2015-03-12 10:44:03 +03:00
2015-03-12 10:44:11 +03:00
return psy - > desc - > get_property ( psy , psp , val ) ;
2015-03-12 10:44:03 +03:00
}
EXPORT_SYMBOL_GPL ( power_supply_get_property ) ;
int power_supply_set_property ( struct power_supply * psy ,
enum power_supply_property psp ,
const union power_supply_propval * val )
{
2015-03-12 10:44:11 +03:00
if ( atomic_read ( & psy - > use_cnt ) < = 0 | | ! psy - > desc - > set_property )
2015-03-12 10:44:03 +03:00
return - ENODEV ;
2015-03-12 10:44:11 +03:00
return psy - > desc - > set_property ( psy , psp , val ) ;
2015-03-12 10:44:03 +03:00
}
EXPORT_SYMBOL_GPL ( power_supply_set_property ) ;
int power_supply_property_is_writeable ( struct power_supply * psy ,
enum power_supply_property psp )
{
2015-03-12 10:44:11 +03:00
if ( atomic_read ( & psy - > use_cnt ) < = 0 | |
! psy - > desc - > property_is_writeable )
2015-03-12 10:44:03 +03:00
return - ENODEV ;
2015-03-12 10:44:11 +03:00
return psy - > desc - > property_is_writeable ( psy , psp ) ;
2015-03-12 10:44:03 +03:00
}
EXPORT_SYMBOL_GPL ( power_supply_property_is_writeable ) ;
void power_supply_external_power_changed ( struct power_supply * psy )
{
2015-03-12 10:44:11 +03:00
if ( atomic_read ( & psy - > use_cnt ) < = 0 | |
! psy - > desc - > external_power_changed )
2015-03-12 10:44:03 +03:00
return ;
2015-03-12 10:44:11 +03:00
psy - > desc - > external_power_changed ( psy ) ;
2015-03-12 10:44:03 +03:00
}
EXPORT_SYMBOL_GPL ( power_supply_external_power_changed ) ;
2011-12-07 21:15:45 +04:00
int power_supply_powers ( struct power_supply * psy , struct device * dev )
{
2015-03-12 10:44:11 +03:00
return sysfs_create_link ( & psy - > dev . kobj , & dev - > kobj , " powers " ) ;
2011-12-07 21:15:45 +04:00
}
EXPORT_SYMBOL_GPL ( power_supply_powers ) ;
2010-05-18 23:49:51 +04:00
static void power_supply_dev_release ( struct device * dev )
{
2015-03-12 10:44:11 +03:00
struct power_supply * psy = container_of ( dev , struct power_supply , dev ) ;
2010-05-18 23:49:51 +04:00
pr_debug ( " device: '%s': %s \n " , dev_name ( dev ) , __func__ ) ;
2015-03-12 10:44:11 +03:00
kfree ( psy ) ;
2010-05-18 23:49:51 +04:00
}
2013-11-19 14:18:03 +04:00
int power_supply_reg_notifier ( struct notifier_block * nb )
{
return atomic_notifier_chain_register ( & power_supply_notifier , nb ) ;
}
EXPORT_SYMBOL_GPL ( power_supply_reg_notifier ) ;
void power_supply_unreg_notifier ( struct notifier_block * nb )
{
atomic_notifier_chain_unregister ( & power_supply_notifier , nb ) ;
}
EXPORT_SYMBOL_GPL ( power_supply_unreg_notifier ) ;
2012-05-09 19:06:47 +04:00
# ifdef CONFIG_THERMAL
static int power_supply_read_temp ( struct thermal_zone_device * tzd ,
2015-07-24 09:12:54 +03:00
int * temp )
2012-05-09 19:06:47 +04:00
{
struct power_supply * psy ;
union power_supply_propval val ;
int ret ;
WARN_ON ( tzd = = NULL ) ;
psy = tzd - > devdata ;
2016-06-10 00:28:39 +03:00
ret = power_supply_get_property ( psy , POWER_SUPPLY_PROP_TEMP , & val ) ;
if ( ret )
return ret ;
2012-05-09 19:06:47 +04:00
/* Convert tenths of degree Celsius to milli degree Celsius. */
2016-06-10 00:28:39 +03:00
* temp = val . intval * 100 ;
2012-05-09 19:06:47 +04:00
return ret ;
}
static struct thermal_zone_device_ops psy_tzd_ops = {
. get_temp = power_supply_read_temp ,
} ;
static int psy_register_thermal ( struct power_supply * psy )
{
int i ;
2015-03-12 10:44:11 +03:00
if ( psy - > desc - > no_thermal )
2014-10-07 19:47:36 +04:00
return 0 ;
2012-05-09 19:06:47 +04:00
/* Register battery zone device psy reports temperature */
2015-03-12 10:44:11 +03:00
for ( i = 0 ; i < psy - > desc - > num_properties ; i + + ) {
if ( psy - > desc - > properties [ i ] = = POWER_SUPPLY_PROP_TEMP ) {
psy - > tzd = thermal_zone_device_register ( psy - > desc - > name ,
0 , 0 , psy , & psy_tzd_ops , NULL , 0 , 0 ) ;
2014-09-04 16:01:33 +04:00
return PTR_ERR_OR_ZERO ( psy - > tzd ) ;
2012-05-09 19:06:47 +04:00
}
}
return 0 ;
}
static void psy_unregister_thermal ( struct power_supply * psy )
{
if ( IS_ERR_OR_NULL ( psy - > tzd ) )
return ;
thermal_zone_device_unregister ( psy - > tzd ) ;
}
2012-10-09 20:55:59 +04:00
/* thermal cooling device callbacks */
static int ps_get_max_charge_cntl_limit ( struct thermal_cooling_device * tcd ,
unsigned long * state )
{
struct power_supply * psy ;
union power_supply_propval val ;
int ret ;
psy = tcd - > devdata ;
2016-06-10 00:28:39 +03:00
ret = power_supply_get_property ( psy ,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX , & val ) ;
if ( ret )
return ret ;
* state = val . intval ;
2012-10-09 20:55:59 +04:00
return ret ;
}
static int ps_get_cur_chrage_cntl_limit ( struct thermal_cooling_device * tcd ,
unsigned long * state )
{
struct power_supply * psy ;
union power_supply_propval val ;
int ret ;
psy = tcd - > devdata ;
2016-06-10 00:28:39 +03:00
ret = power_supply_get_property ( psy ,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT , & val ) ;
if ( ret )
return ret ;
* state = val . intval ;
2012-10-09 20:55:59 +04:00
return ret ;
}
static int ps_set_cur_charge_cntl_limit ( struct thermal_cooling_device * tcd ,
unsigned long state )
{
struct power_supply * psy ;
union power_supply_propval val ;
int ret ;
psy = tcd - > devdata ;
val . intval = state ;
2015-03-12 10:44:11 +03:00
ret = psy - > desc - > set_property ( psy ,
2012-10-09 20:55:59 +04:00
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT , & val ) ;
return ret ;
}
static struct thermal_cooling_device_ops psy_tcd_ops = {
. get_max_state = ps_get_max_charge_cntl_limit ,
. get_cur_state = ps_get_cur_chrage_cntl_limit ,
. set_cur_state = ps_set_cur_charge_cntl_limit ,
} ;
static int psy_register_cooler ( struct power_supply * psy )
{
int i ;
/* Register for cooling device if psy can control charging */
2015-03-12 10:44:11 +03:00
for ( i = 0 ; i < psy - > desc - > num_properties ; i + + ) {
if ( psy - > desc - > properties [ i ] = =
2012-10-09 20:55:59 +04:00
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT ) {
psy - > tcd = thermal_cooling_device_register (
2015-03-12 10:44:11 +03:00
( char * ) psy - > desc - > name ,
2012-10-09 20:55:59 +04:00
psy , & psy_tcd_ops ) ;
2014-09-04 16:01:33 +04:00
return PTR_ERR_OR_ZERO ( psy - > tcd ) ;
2012-10-09 20:55:59 +04:00
}
}
return 0 ;
}
static void psy_unregister_cooler ( struct power_supply * psy )
{
if ( IS_ERR_OR_NULL ( psy - > tcd ) )
return ;
thermal_cooling_device_unregister ( psy - > tcd ) ;
}
2012-05-09 19:06:47 +04:00
# else
static int psy_register_thermal ( struct power_supply * psy )
{
return 0 ;
}
static void psy_unregister_thermal ( struct power_supply * psy )
{
}
2012-10-09 20:55:59 +04:00
static int psy_register_cooler ( struct power_supply * psy )
{
return 0 ;
}
static void psy_unregister_cooler ( struct power_supply * psy )
{
}
2012-05-09 19:06:47 +04:00
# endif
2015-03-12 10:44:11 +03:00
static struct power_supply * __must_check
__power_supply_register ( struct device * parent ,
const struct power_supply_desc * desc ,
2015-03-12 10:44:02 +03:00
const struct power_supply_config * cfg ,
bool ws )
2007-05-04 00:27:45 +04:00
{
2010-05-18 23:49:51 +04:00
struct device * dev ;
2015-03-12 10:44:11 +03:00
struct power_supply * psy ;
2010-05-18 23:49:51 +04:00
int rc ;
2007-05-04 00:27:45 +04:00
2015-05-19 10:13:02 +03:00
if ( ! parent )
pr_warn ( " %s: Expected proper parent device for '%s' \n " ,
__func__ , desc - > name ) ;
2015-03-12 10:44:11 +03:00
psy = kzalloc ( sizeof ( * psy ) , GFP_KERNEL ) ;
if ( ! psy )
return ERR_PTR ( - ENOMEM ) ;
dev = & psy - > dev ;
2007-05-04 00:27:45 +04:00
2010-05-18 23:49:51 +04:00
device_initialize ( dev ) ;
2007-05-04 00:27:45 +04:00
2010-05-18 23:49:51 +04:00
dev - > class = power_supply_class ;
dev - > type = & power_supply_dev_type ;
dev - > parent = parent ;
dev - > release = power_supply_dev_release ;
dev_set_drvdata ( dev , psy ) ;
2015-03-12 10:44:11 +03:00
psy - > desc = desc ;
2015-03-12 10:44:02 +03:00
if ( cfg ) {
psy - > drv_data = cfg - > drv_data ;
psy - > of_node = cfg - > of_node ;
psy - > supplied_to = cfg - > supplied_to ;
psy - > num_supplicants = cfg - > num_supplicants ;
}
2010-05-18 23:49:51 +04:00
2015-03-12 10:44:11 +03:00
rc = dev_set_name ( dev , " %s " , desc - > name ) ;
2013-11-22 21:54:28 +04:00
if ( rc )
goto dev_set_name_failed ;
2011-02-21 17:34:19 +03:00
INIT_WORK ( & psy - > changed_work , power_supply_changed_work ) ;
2015-05-19 10:13:02 +03:00
INIT_DELAYED_WORK ( & psy - > deferred_register_work ,
power_supply_deferred_register_work ) ;
2011-02-21 17:34:19 +03:00
2013-04-02 01:45:55 +04:00
rc = power_supply_check_supplies ( psy ) ;
if ( rc ) {
dev_info ( dev , " Not all required supplies found, defer probe \n " ) ;
goto check_supplies_failed ;
}
2013-08-03 00:38:02 +04:00
spin_lock_init ( & psy - > changed_lock ) ;
2014-05-28 11:23:37 +04:00
rc = device_init_wakeup ( dev , ws ) ;
2013-08-03 00:38:02 +04:00
if ( rc )
goto wakeup_init_failed ;
2010-05-18 23:49:51 +04:00
rc = device_add ( dev ) ;
2007-05-04 00:27:45 +04:00
if ( rc )
2010-05-18 23:49:51 +04:00
goto device_add_failed ;
2012-05-09 19:06:47 +04:00
rc = psy_register_thermal ( psy ) ;
if ( rc )
goto register_thermal_failed ;
2012-10-09 20:55:59 +04:00
rc = psy_register_cooler ( psy ) ;
if ( rc )
goto register_cooler_failed ;
2007-05-04 00:27:45 +04:00
rc = power_supply_create_triggers ( psy ) ;
if ( rc )
goto create_triggers_failed ;
2015-05-19 10:13:01 +03:00
/*
* Update use_cnt after any uevents ( most notably from device_add ( ) ) .
* We are here still during driver ' s probe but
* the power_supply_uevent ( ) calls back driver ' s get_property
* method so :
* 1. Driver did not assigned the returned struct power_supply ,
* 2. Driver could not finish initialization ( anything in its probe
* after calling power_supply_register ( ) ) .
*/
atomic_inc ( & psy - > use_cnt ) ;
2016-06-22 18:45:52 +03:00
psy - > initialized = true ;
2015-05-19 10:13:02 +03:00
queue_delayed_work ( system_power_efficient_wq ,
& psy - > deferred_register_work ,
POWER_SUPPLY_DEFERRED_REGISTER_TIME ) ;
2007-05-04 00:27:45 +04:00
2015-03-12 10:44:11 +03:00
return psy ;
2007-05-04 00:27:45 +04:00
create_triggers_failed :
2012-10-09 20:55:59 +04:00
psy_unregister_cooler ( psy ) ;
register_cooler_failed :
2012-05-09 19:06:47 +04:00
psy_unregister_thermal ( psy ) ;
register_thermal_failed :
2010-11-19 21:41:58 +03:00
device_del ( dev ) ;
2010-05-18 23:49:51 +04:00
device_add_failed :
2013-11-22 21:54:28 +04:00
wakeup_init_failed :
2013-04-02 01:45:55 +04:00
check_supplies_failed :
2013-11-22 21:54:28 +04:00
dev_set_name_failed :
2010-11-19 21:41:58 +03:00
put_device ( dev ) ;
2015-03-12 10:44:11 +03:00
return ERR_PTR ( rc ) ;
2007-05-04 00:27:45 +04:00
}
2014-05-28 11:23:37 +04:00
2015-03-12 10:44:11 +03:00
/**
* power_supply_register ( ) - Register new power supply
2015-05-19 10:13:02 +03:00
* @ parent : Device to be a parent of power supply ' s device , usually
* the device which probe function calls this
2015-03-12 10:44:11 +03:00
* @ desc : Description of power supply , must be valid through whole
* lifetime of this power supply
* @ cfg : Run - time specific configuration accessed during registering ,
* may be NULL
*
* Return : A pointer to newly allocated power_supply on success
* or ERR_PTR otherwise .
* Use power_supply_unregister ( ) on returned power_supply pointer to release
* resources .
*/
struct power_supply * __must_check power_supply_register ( struct device * parent ,
const struct power_supply_desc * desc ,
2015-03-12 10:44:02 +03:00
const struct power_supply_config * cfg )
2014-05-28 11:23:37 +04:00
{
2015-03-12 10:44:11 +03:00
return __power_supply_register ( parent , desc , cfg , true ) ;
2014-05-28 11:23:37 +04:00
}
2009-07-30 17:42:31 +04:00
EXPORT_SYMBOL_GPL ( power_supply_register ) ;
2007-05-04 00:27:45 +04:00
2015-03-12 10:44:11 +03:00
/**
2015-06-18 22:35:26 +03:00
* power_supply_register_no_ws ( ) - Register new non - waking - source power supply
2015-05-19 10:13:02 +03:00
* @ parent : Device to be a parent of power supply ' s device , usually
* the device which probe function calls this
2015-03-12 10:44:11 +03:00
* @ desc : Description of power supply , must be valid through whole
* lifetime of this power supply
* @ cfg : Run - time specific configuration accessed during registering ,
* may be NULL
*
* Return : A pointer to newly allocated power_supply on success
* or ERR_PTR otherwise .
* Use power_supply_unregister ( ) on returned power_supply pointer to release
* resources .
*/
struct power_supply * __must_check
power_supply_register_no_ws ( struct device * parent ,
const struct power_supply_desc * desc ,
2015-03-12 10:44:02 +03:00
const struct power_supply_config * cfg )
2014-05-28 11:23:37 +04:00
{
2015-03-12 10:44:11 +03:00
return __power_supply_register ( parent , desc , cfg , false ) ;
2014-05-28 11:23:37 +04:00
}
EXPORT_SYMBOL_GPL ( power_supply_register_no_ws ) ;
2015-02-24 07:33:50 +03:00
static void devm_power_supply_release ( struct device * dev , void * res )
{
struct power_supply * * psy = res ;
power_supply_unregister ( * psy ) ;
}
2015-03-12 10:44:11 +03:00
/**
2015-06-18 22:35:26 +03:00
* devm_power_supply_register ( ) - Register managed power supply
2015-05-19 10:13:02 +03:00
* @ parent : Device to be a parent of power supply ' s device , usually
* the device which probe function calls this
2015-03-12 10:44:11 +03:00
* @ desc : Description of power supply , must be valid through whole
* lifetime of this power supply
* @ cfg : Run - time specific configuration accessed during registering ,
* may be NULL
*
* Return : A pointer to newly allocated power_supply on success
* or ERR_PTR otherwise .
* The returned power_supply pointer will be automatically unregistered
* on driver detach .
*/
struct power_supply * __must_check
devm_power_supply_register ( struct device * parent ,
const struct power_supply_desc * desc ,
2015-03-12 10:44:02 +03:00
const struct power_supply_config * cfg )
2015-02-24 07:33:50 +03:00
{
2015-03-12 10:44:11 +03:00
struct power_supply * * ptr , * psy ;
ptr = devres_alloc ( devm_power_supply_release , sizeof ( * ptr ) , GFP_KERNEL ) ;
2015-02-24 07:33:50 +03:00
if ( ! ptr )
2015-03-12 10:44:11 +03:00
return ERR_PTR ( - ENOMEM ) ;
psy = __power_supply_register ( parent , desc , cfg , true ) ;
if ( IS_ERR ( psy ) ) {
2015-02-24 07:33:50 +03:00
devres_free ( ptr ) ;
2015-03-12 10:44:11 +03:00
} else {
2015-02-24 07:33:50 +03:00
* ptr = psy ;
devres_add ( parent , ptr ) ;
}
2015-03-12 10:44:11 +03:00
return psy ;
2015-02-24 07:33:50 +03:00
}
EXPORT_SYMBOL_GPL ( devm_power_supply_register ) ;
2015-03-12 10:44:11 +03:00
/**
2015-06-18 22:35:26 +03:00
* devm_power_supply_register_no_ws ( ) - Register managed non - waking - source power supply
2015-05-19 10:13:02 +03:00
* @ parent : Device to be a parent of power supply ' s device , usually
* the device which probe function calls this
2015-03-12 10:44:11 +03:00
* @ desc : Description of power supply , must be valid through whole
* lifetime of this power supply
* @ cfg : Run - time specific configuration accessed during registering ,
* may be NULL
*
* Return : A pointer to newly allocated power_supply on success
* or ERR_PTR otherwise .
* The returned power_supply pointer will be automatically unregistered
* on driver detach .
*/
struct power_supply * __must_check
devm_power_supply_register_no_ws ( struct device * parent ,
const struct power_supply_desc * desc ,
2015-03-12 10:44:02 +03:00
const struct power_supply_config * cfg )
2015-02-24 07:33:50 +03:00
{
2015-03-12 10:44:11 +03:00
struct power_supply * * ptr , * psy ;
ptr = devres_alloc ( devm_power_supply_release , sizeof ( * ptr ) , GFP_KERNEL ) ;
2015-02-24 07:33:50 +03:00
if ( ! ptr )
2015-03-12 10:44:11 +03:00
return ERR_PTR ( - ENOMEM ) ;
psy = __power_supply_register ( parent , desc , cfg , false ) ;
if ( IS_ERR ( psy ) ) {
2015-02-24 07:33:50 +03:00
devres_free ( ptr ) ;
2015-03-12 10:44:11 +03:00
} else {
2015-02-24 07:33:50 +03:00
* ptr = psy ;
devres_add ( parent , ptr ) ;
}
2015-03-12 10:44:11 +03:00
return psy ;
2015-02-24 07:33:50 +03:00
}
EXPORT_SYMBOL_GPL ( devm_power_supply_register_no_ws ) ;
2015-03-12 10:44:11 +03:00
/**
* power_supply_unregister ( ) - Remove this power supply from system
* @ psy : Pointer to power supply to unregister
*
* Remove this power supply from the system . The resources of power supply
* will be freed here or on last power_supply_put ( ) call .
*/
2007-05-04 00:27:45 +04:00
void power_supply_unregister ( struct power_supply * psy )
{
2015-03-12 10:44:03 +03:00
WARN_ON ( atomic_dec_return ( & psy - > use_cnt ) ) ;
2010-12-11 19:51:45 +03:00
cancel_work_sync ( & psy - > changed_work ) ;
2015-05-19 10:13:02 +03:00
cancel_delayed_work_sync ( & psy - > deferred_register_work ) ;
2015-03-12 10:44:11 +03:00
sysfs_remove_link ( & psy - > dev . kobj , " powers " ) ;
2007-05-04 00:27:45 +04:00
power_supply_remove_triggers ( psy ) ;
2012-10-09 20:55:59 +04:00
psy_unregister_cooler ( psy ) ;
2012-05-09 19:06:47 +04:00
psy_unregister_thermal ( psy ) ;
2015-03-12 10:44:11 +03:00
device_init_wakeup ( & psy - > dev , false ) ;
device_unregister ( & psy - > dev ) ;
2007-05-04 00:27:45 +04:00
}
2009-07-30 17:42:31 +04:00
EXPORT_SYMBOL_GPL ( power_supply_unregister ) ;
2007-05-04 00:27:45 +04:00
2015-03-12 10:44:01 +03:00
void * power_supply_get_drvdata ( struct power_supply * psy )
{
return psy - > drv_data ;
}
EXPORT_SYMBOL_GPL ( power_supply_get_drvdata ) ;
2007-05-04 00:27:45 +04:00
static int __init power_supply_class_init ( void )
{
power_supply_class = class_create ( THIS_MODULE , " power_supply " ) ;
if ( IS_ERR ( power_supply_class ) )
return PTR_ERR ( power_supply_class ) ;
power_supply_class - > dev_uevent = power_supply_uevent ;
2010-05-18 23:49:51 +04:00
power_supply_init_attrs ( & power_supply_dev_type ) ;
2007-05-04 00:27:45 +04:00
return 0 ;
}
static void __exit power_supply_class_exit ( void )
{
class_destroy ( power_supply_class ) ;
}
subsys_initcall ( power_supply_class_init ) ;
module_exit ( power_supply_class_exit ) ;
MODULE_DESCRIPTION ( " Universal power supply monitor class " ) ;
MODULE_AUTHOR ( " Ian Molton <spyro@f2s.com>, "
" Szabolcs Gyurko, "
" Anton Vorontsov <cbou@mail.ru> " ) ;
MODULE_LICENSE ( " GPL " ) ;