2007-05-04 00:47:40 +04:00
/*
* Battery class driver for Apple PMU
*
* Copyright © 2006 David Woodhouse < dwmw2 @ infradead . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/err.h>
# include <linux/power_supply.h>
# include <linux/adb.h>
# include <linux/pmu.h>
static struct pmu_battery_dev {
struct power_supply bat ;
struct pmu_battery_info * pbi ;
char name [ 16 ] ;
int propval ;
} * pbats [ PMU_MAX_BATTERIES ] ;
# define to_pmu_battery_dev(x) container_of(x, struct pmu_battery_dev, bat)
/*********************************************************************
* Power
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int pmu_get_ac_prop ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
switch ( psp ) {
case POWER_SUPPLY_PROP_ONLINE :
val - > intval = ( ! ! ( pmu_power_flags & PMU_PWR_AC_PRESENT ) ) | |
( pmu_battery_count = = 0 ) ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static enum power_supply_property pmu_ac_props [ ] = {
POWER_SUPPLY_PROP_ONLINE ,
} ;
static struct power_supply pmu_ac = {
. name = " pmu-ac " ,
. type = POWER_SUPPLY_TYPE_MAINS ,
. properties = pmu_ac_props ,
. num_properties = ARRAY_SIZE ( pmu_ac_props ) ,
. get_property = pmu_get_ac_prop ,
} ;
/*********************************************************************
* Battery properties
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * pmu_batt_types [ ] = {
" Smart " , " Comet " , " Hooper " , " Unknown "
} ;
static char * pmu_bat_get_model_name ( struct pmu_battery_info * pbi )
{
switch ( pbi - > flags & PMU_BATT_TYPE_MASK ) {
case PMU_BATT_TYPE_SMART :
return pmu_batt_types [ 0 ] ;
case PMU_BATT_TYPE_COMET :
return pmu_batt_types [ 1 ] ;
case PMU_BATT_TYPE_HOOPER :
return pmu_batt_types [ 2 ] ;
default : break ;
}
return pmu_batt_types [ 3 ] ;
}
static int pmu_bat_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
struct pmu_battery_dev * pbat = to_pmu_battery_dev ( psy ) ;
struct pmu_battery_info * pbi = pbat - > pbi ;
switch ( psp ) {
case POWER_SUPPLY_PROP_STATUS :
if ( pbi - > flags & PMU_BATT_CHARGING )
val - > intval = POWER_SUPPLY_STATUS_CHARGING ;
else
val - > intval = POWER_SUPPLY_STATUS_DISCHARGING ;
break ;
case POWER_SUPPLY_PROP_PRESENT :
val - > intval = ! ! ( pbi - > flags & PMU_BATT_PRESENT ) ;
break ;
case POWER_SUPPLY_PROP_MODEL_NAME :
val - > strval = pmu_bat_get_model_name ( pbi ) ;
break ;
case POWER_SUPPLY_PROP_ENERGY_AVG :
val - > intval = pbi - > charge * 1000 ; /* mWh -> µWh */
break ;
case POWER_SUPPLY_PROP_ENERGY_FULL :
val - > intval = pbi - > max_charge * 1000 ; /* mWh -> µWh */
break ;
case POWER_SUPPLY_PROP_CURRENT_AVG :
val - > intval = pbi - > amperage * 1000 ; /* mA -> µA */
break ;
case POWER_SUPPLY_PROP_VOLTAGE_AVG :
val - > intval = pbi - > voltage * 1000 ; /* mV -> µV */
break ;
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG :
val - > intval = pbi - > time_remaining ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static enum power_supply_property pmu_bat_props [ ] = {
POWER_SUPPLY_PROP_STATUS ,
POWER_SUPPLY_PROP_PRESENT ,
POWER_SUPPLY_PROP_MODEL_NAME ,
POWER_SUPPLY_PROP_ENERGY_AVG ,
POWER_SUPPLY_PROP_ENERGY_FULL ,
POWER_SUPPLY_PROP_CURRENT_AVG ,
POWER_SUPPLY_PROP_VOLTAGE_AVG ,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG ,
} ;
/*********************************************************************
* Initialisation
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct platform_device * bat_pdev ;
static int __init pmu_bat_init ( void )
{
int ret ;
int i ;
bat_pdev = platform_device_register_simple ( " pmu-battery " ,
0 , NULL , 0 ) ;
if ( IS_ERR ( bat_pdev ) ) {
ret = PTR_ERR ( bat_pdev ) ;
goto pdev_register_failed ;
}
ret = power_supply_register ( & bat_pdev - > dev , & pmu_ac ) ;
if ( ret )
goto ac_register_failed ;
for ( i = 0 ; i < pmu_battery_count ; i + + ) {
struct pmu_battery_dev * pbat = kzalloc ( sizeof ( * pbat ) ,
GFP_KERNEL ) ;
if ( ! pbat )
break ;
2008-05-03 00:41:56 +04:00
sprintf ( pbat - > name , " PMU_battery_%d " , i ) ;
2007-05-04 00:47:40 +04:00
pbat - > bat . name = pbat - > name ;
pbat - > bat . properties = pmu_bat_props ;
pbat - > bat . num_properties = ARRAY_SIZE ( pmu_bat_props ) ;
pbat - > bat . get_property = pmu_bat_get_property ;
pbat - > pbi = & pmu_batteries [ i ] ;
ret = power_supply_register ( & bat_pdev - > dev , & pbat - > bat ) ;
if ( ret ) {
kfree ( pbat ) ;
goto battery_register_failed ;
}
pbats [ i ] = pbat ;
}
goto success ;
battery_register_failed :
while ( i - - ) {
if ( ! pbats [ i ] )
continue ;
power_supply_unregister ( & pbats [ i ] - > bat ) ;
kfree ( pbats [ i ] ) ;
}
power_supply_unregister ( & pmu_ac ) ;
ac_register_failed :
platform_device_unregister ( bat_pdev ) ;
pdev_register_failed :
success :
return ret ;
}
static void __exit pmu_bat_exit ( void )
{
int i ;
for ( i = 0 ; i < PMU_MAX_BATTERIES ; i + + ) {
if ( ! pbats [ i ] )
continue ;
power_supply_unregister ( & pbats [ i ] - > bat ) ;
kfree ( pbats [ i ] ) ;
}
power_supply_unregister ( & pmu_ac ) ;
platform_device_unregister ( bat_pdev ) ;
}
module_init ( pmu_bat_init ) ;
module_exit ( pmu_bat_exit ) ;
MODULE_AUTHOR ( " David Woodhouse <dwmw2@infradead.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " PMU battery driver " ) ;