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>
# include <linux/device.h>
# include <linux/err.h>
# include <linux/power_supply.h>
# 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
2008-01-22 08:58:22 +03:00
static int __power_supply_changed_work ( struct device * dev , void * data )
{
struct power_supply * psy = ( struct power_supply * ) data ;
struct power_supply * pst = dev_get_drvdata ( dev ) ;
int i ;
for ( i = 0 ; i < psy - > num_supplicants ; i + + )
if ( ! strcmp ( psy - > supplied_to [ i ] , pst - > name ) ) {
if ( pst - > external_power_changed )
pst - > external_power_changed ( pst ) ;
}
return 0 ;
}
2007-05-04 00:27:45 +04:00
static void power_supply_changed_work ( struct work_struct * work )
{
struct power_supply * psy = container_of ( work , struct power_supply ,
changed_work ) ;
2008-04-29 11:58:29 +04:00
dev_dbg ( psy - > dev , " %s \n " , __func__ ) ;
2007-05-04 00:27:45 +04:00
2008-05-23 01:21:08 +04:00
class_for_each_device ( power_supply_class , NULL , psy ,
2008-01-22 08:58:22 +03:00
__power_supply_changed_work ) ;
2007-05-04 00:27:45 +04:00
power_supply_update_leds ( psy ) ;
kobject_uevent ( & psy - > dev - > kobj , KOBJ_CHANGE ) ;
}
void power_supply_changed ( struct power_supply * psy )
{
2008-04-29 11:58:29 +04:00
dev_dbg ( psy - > dev , " %s \n " , __func__ ) ;
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
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 , } ;
2008-01-22 08:58:22 +03:00
struct power_supply * psy = ( struct power_supply * ) data ;
struct power_supply * epsy = dev_get_drvdata ( dev ) ;
int i ;
for ( i = 0 ; i < epsy - > num_supplicants ; i + + ) {
if ( ! strcmp ( epsy - > supplied_to [ i ] , psy - > name ) ) {
if ( epsy - > get_property ( epsy ,
POWER_SUPPLY_PROP_ONLINE , & ret ) )
continue ;
if ( ret . intval )
return ret . intval ;
2007-05-04 00:27:45 +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
2008-04-29 11:58:29 +04: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 ) ;
if ( psy - > type ! = POWER_SUPPLY_TYPE_BATTERY ) {
if ( psy - > get_property ( psy , POWER_SUPPLY_PROP_ONLINE , & ret ) )
return 0 ;
if ( ret . intval )
return ret . intval ;
}
return 0 ;
}
int power_supply_is_system_supplied ( void )
{
int error ;
error = class_for_each_device ( power_supply_class , NULL , NULL ,
__power_supply_is_system_supplied ) ;
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 )
{
if ( psy - > type = = POWER_SUPPLY_TYPE_BATTERY & & psy - > set_charged ) {
psy - > set_charged ( psy ) ;
return 0 ;
}
return - EINVAL ;
}
EXPORT_SYMBOL_GPL ( power_supply_set_battery_charged ) ;
static int power_supply_match_device_by_name ( struct device * dev , void * data )
{
const char * name = data ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
return strcmp ( psy - > name , name ) = = 0 ;
}
struct power_supply * power_supply_get_by_name ( char * name )
{
struct device * dev = class_find_device ( power_supply_class , NULL , name ,
power_supply_match_device_by_name ) ;
return dev ? dev_get_drvdata ( dev ) : NULL ;
}
EXPORT_SYMBOL_GPL ( power_supply_get_by_name ) ;
2007-05-04 00:27:45 +04:00
int power_supply_register ( struct device * parent , struct power_supply * psy )
{
int rc = 0 ;
2008-07-22 07:03:34 +04:00
psy - > dev = device_create ( power_supply_class , parent , 0 , psy ,
" %s " , psy - > name ) ;
2007-05-04 00:27:45 +04:00
if ( IS_ERR ( psy - > dev ) ) {
rc = PTR_ERR ( psy - > dev ) ;
goto dev_create_failed ;
}
INIT_WORK ( & psy - > changed_work , power_supply_changed_work ) ;
rc = power_supply_create_attrs ( psy ) ;
if ( rc )
goto create_attrs_failed ;
rc = power_supply_create_triggers ( psy ) ;
if ( rc )
goto create_triggers_failed ;
power_supply_changed ( psy ) ;
goto success ;
create_triggers_failed :
power_supply_remove_attrs ( psy ) ;
create_attrs_failed :
device_unregister ( psy - > dev ) ;
dev_create_failed :
success :
return rc ;
}
2009-07-30 17:42:31 +04:00
EXPORT_SYMBOL_GPL ( power_supply_register ) ;
2007-05-04 00:27:45 +04:00
void power_supply_unregister ( struct power_supply * psy )
{
flush_scheduled_work ( ) ;
power_supply_remove_triggers ( psy ) ;
power_supply_remove_attrs ( psy ) ;
device_unregister ( psy - > dev ) ;
}
2009-07-30 17:42:31 +04:00
EXPORT_SYMBOL_GPL ( power_supply_unregister ) ;
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 ;
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 " ) ;