2007-05-04 00:51:18 +04:00
/*
* Battery driver for One Laptop Per Child board .
*
2010-08-09 21:13:09 +04:00
* Copyright © 2006 - 2010 David Woodhouse < dwmw2 @ infradead . org >
2007-05-04 00:51:18 +04:00
*
* 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 .
*/
2009-06-30 10:14:00 +04:00
# include <linux/kernel.h>
2007-05-04 00:51:18 +04:00
# include <linux/module.h>
2009-06-30 10:15:26 +04:00
# include <linux/types.h>
2007-05-04 00:51:18 +04:00
# include <linux/err.h>
2009-06-30 10:15:26 +04:00
# include <linux/device.h>
2007-05-04 00:51:18 +04:00
# include <linux/platform_device.h>
# include <linux/power_supply.h>
# include <linux/jiffies.h>
# include <linux/sched.h>
2012-07-11 12:16:29 +04:00
# include <linux/olpc-ec.h>
2007-05-04 00:51:18 +04:00
# include <asm/olpc.h>
# define EC_BAT_VOLTAGE 0x10 /* uint16_t, *9.76/32, mV */
# define EC_BAT_CURRENT 0x11 /* int16_t, *15.625/120, mA */
2008-05-15 03:20:38 +04:00
# define EC_BAT_ACR 0x12 /* int16_t, *6250/15, µAh */
2007-05-04 00:51:18 +04:00
# define EC_BAT_TEMP 0x13 /* uint16_t, *100/256, °C */
# define EC_AMB_TEMP 0x14 /* uint16_t, *100/256, °C */
# define EC_BAT_STATUS 0x15 /* uint8_t, bitmask */
# define EC_BAT_SOC 0x16 /* uint8_t, percentage */
# define EC_BAT_SERIAL 0x17 /* uint8_t[6] */
# define EC_BAT_EEPROM 0x18 /* uint8_t adr as input, uint8_t output */
# define EC_BAT_ERRCODE 0x1f /* uint8_t, bitmask */
# define BAT_STAT_PRESENT 0x01
# define BAT_STAT_FULL 0x02
# define BAT_STAT_LOW 0x04
# define BAT_STAT_DESTROY 0x08
# define BAT_STAT_AC 0x10
# define BAT_STAT_CHARGING 0x20
# define BAT_STAT_DISCHARGING 0x40
2009-06-30 10:16:17 +04:00
# define BAT_STAT_TRICKLE 0x80
2007-05-04 00:51:18 +04:00
# define BAT_ERR_INFOFAIL 0x02
# define BAT_ERR_OVERVOLTAGE 0x04
# define BAT_ERR_OVERTEMP 0x05
# define BAT_ERR_GAUGESTOP 0x06
# define BAT_ERR_OUT_OF_CONTROL 0x07
# define BAT_ERR_ID_FAIL 0x09
# define BAT_ERR_ACR_FAIL 0x10
# define BAT_ADDR_MFR_TYPE 0x5F
/*********************************************************************
* Power
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int olpc_ac_get_prop ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
int ret = 0 ;
uint8_t status ;
switch ( psp ) {
case POWER_SUPPLY_PROP_ONLINE :
ret = olpc_ec_cmd ( EC_BAT_STATUS , NULL , 0 , & status , 1 ) ;
if ( ret )
return ret ;
val - > intval = ! ! ( status & BAT_STAT_AC ) ;
break ;
default :
ret = - EINVAL ;
break ;
}
return ret ;
}
static enum power_supply_property olpc_ac_props [ ] = {
POWER_SUPPLY_PROP_ONLINE ,
} ;
static struct power_supply olpc_ac = {
. name = " olpc-ac " ,
. type = POWER_SUPPLY_TYPE_MAINS ,
. properties = olpc_ac_props ,
. num_properties = ARRAY_SIZE ( olpc_ac_props ) ,
. get_property = olpc_ac_get_prop ,
} ;
2008-05-04 09:31:42 +04:00
static char bat_serial [ 17 ] ; /* Ick */
2008-05-03 00:41:59 +04:00
static int olpc_bat_get_status ( union power_supply_propval * val , uint8_t ec_byte )
{
if ( olpc_platform_info . ecver > 0x44 ) {
2009-06-30 10:16:17 +04:00
if ( ec_byte & ( BAT_STAT_CHARGING | BAT_STAT_TRICKLE ) )
2008-05-03 00:41:59 +04:00
val - > intval = POWER_SUPPLY_STATUS_CHARGING ;
else if ( ec_byte & BAT_STAT_DISCHARGING )
val - > intval = POWER_SUPPLY_STATUS_DISCHARGING ;
else if ( ec_byte & BAT_STAT_FULL )
val - > intval = POWER_SUPPLY_STATUS_FULL ;
else /* er,... */
val - > intval = POWER_SUPPLY_STATUS_NOT_CHARGING ;
} else {
/* Older EC didn't report charge/discharge bits */
if ( ! ( ec_byte & BAT_STAT_AC ) ) /* No AC means discharging */
val - > intval = POWER_SUPPLY_STATUS_DISCHARGING ;
else if ( ec_byte & BAT_STAT_FULL )
val - > intval = POWER_SUPPLY_STATUS_FULL ;
else /* Not _necessarily_ true but EC doesn't tell all yet */
val - > intval = POWER_SUPPLY_STATUS_CHARGING ;
}
return 0 ;
}
static int olpc_bat_get_health ( union power_supply_propval * val )
{
uint8_t ec_byte ;
int ret ;
ret = olpc_ec_cmd ( EC_BAT_ERRCODE , NULL , 0 , & ec_byte , 1 ) ;
if ( ret )
return ret ;
switch ( ec_byte ) {
case 0 :
val - > intval = POWER_SUPPLY_HEALTH_GOOD ;
break ;
case BAT_ERR_OVERTEMP :
val - > intval = POWER_SUPPLY_HEALTH_OVERHEAT ;
break ;
case BAT_ERR_OVERVOLTAGE :
val - > intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE ;
break ;
case BAT_ERR_INFOFAIL :
case BAT_ERR_OUT_OF_CONTROL :
case BAT_ERR_ID_FAIL :
case BAT_ERR_ACR_FAIL :
val - > intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE ;
break ;
default :
/* Eep. We don't know this failure code */
ret = - EIO ;
}
return ret ;
}
static int olpc_bat_get_mfr ( union power_supply_propval * val )
{
uint8_t ec_byte ;
int ret ;
ec_byte = BAT_ADDR_MFR_TYPE ;
ret = olpc_ec_cmd ( EC_BAT_EEPROM , & ec_byte , 1 , & ec_byte , 1 ) ;
if ( ret )
return ret ;
switch ( ec_byte > > 4 ) {
case 1 :
val - > strval = " Gold Peak " ;
break ;
case 2 :
val - > strval = " BYD " ;
break ;
default :
val - > strval = " Unknown " ;
break ;
}
return ret ;
}
static int olpc_bat_get_tech ( union power_supply_propval * val )
{
uint8_t ec_byte ;
int ret ;
ec_byte = BAT_ADDR_MFR_TYPE ;
ret = olpc_ec_cmd ( EC_BAT_EEPROM , & ec_byte , 1 , & ec_byte , 1 ) ;
if ( ret )
return ret ;
switch ( ec_byte & 0xf ) {
case 1 :
val - > intval = POWER_SUPPLY_TECHNOLOGY_NiMH ;
break ;
case 2 :
val - > intval = POWER_SUPPLY_TECHNOLOGY_LiFe ;
break ;
default :
val - > intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN ;
break ;
}
return ret ;
}
2010-12-11 01:05:19 +03:00
static int olpc_bat_get_charge_full_design ( union power_supply_propval * val )
{
uint8_t ec_byte ;
union power_supply_propval tech ;
int ret , mfr ;
ret = olpc_bat_get_tech ( & tech ) ;
if ( ret )
return ret ;
ec_byte = BAT_ADDR_MFR_TYPE ;
ret = olpc_ec_cmd ( EC_BAT_EEPROM , & ec_byte , 1 , & ec_byte , 1 ) ;
if ( ret )
return ret ;
mfr = ec_byte > > 4 ;
switch ( tech . intval ) {
case POWER_SUPPLY_TECHNOLOGY_NiMH :
switch ( mfr ) {
case 1 : /* Gold Peak */
val - > intval = 3000000 * .8 ;
break ;
default :
return - EIO ;
}
break ;
case POWER_SUPPLY_TECHNOLOGY_LiFe :
switch ( mfr ) {
2012-07-16 01:43:51 +04:00
case 1 : /* Gold Peak, fall through */
2010-12-11 01:05:19 +03:00
case 2 : /* BYD */
2012-07-16 01:43:51 +04:00
val - > intval = 2800000 ;
2010-12-11 01:05:19 +03:00
break ;
default :
return - EIO ;
}
break ;
default :
return - EIO ;
}
return ret ;
}
2010-12-11 01:05:20 +03:00
static int olpc_bat_get_charge_now ( union power_supply_propval * val )
{
uint8_t soc ;
union power_supply_propval full ;
int ret ;
ret = olpc_ec_cmd ( EC_BAT_SOC , NULL , 0 , & soc , 1 ) ;
if ( ret )
return ret ;
ret = olpc_bat_get_charge_full_design ( & full ) ;
if ( ret )
return ret ;
val - > intval = soc * ( full . intval / 100 ) ;
return 0 ;
}
2012-07-16 01:43:25 +04:00
static int olpc_bat_get_voltage_max_design ( union power_supply_propval * val )
{
uint8_t ec_byte ;
union power_supply_propval tech ;
int mfr ;
int ret ;
ret = olpc_bat_get_tech ( & tech ) ;
if ( ret )
return ret ;
ec_byte = BAT_ADDR_MFR_TYPE ;
ret = olpc_ec_cmd ( EC_BAT_EEPROM , & ec_byte , 1 , & ec_byte , 1 ) ;
if ( ret )
return ret ;
mfr = ec_byte > > 4 ;
switch ( tech . intval ) {
case POWER_SUPPLY_TECHNOLOGY_NiMH :
switch ( mfr ) {
case 1 : /* Gold Peak */
val - > intval = 6000000 ;
break ;
default :
return - EIO ;
}
break ;
case POWER_SUPPLY_TECHNOLOGY_LiFe :
switch ( mfr ) {
case 1 : /* Gold Peak */
val - > intval = 6400000 ;
break ;
case 2 : /* BYD */
val - > intval = 6500000 ;
break ;
default :
return - EIO ;
}
break ;
default :
return - EIO ;
}
return ret ;
}
2007-05-04 00:51:18 +04:00
/*********************************************************************
* Battery properties
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int olpc_bat_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
int ret = 0 ;
2008-10-16 09:01:23 +04:00
__be16 ec_word ;
2007-05-04 00:51:18 +04:00
uint8_t ec_byte ;
2008-10-16 09:01:23 +04:00
__be64 ser_buf ;
2007-05-04 00:51:18 +04:00
ret = olpc_ec_cmd ( EC_BAT_STATUS , NULL , 0 , & ec_byte , 1 ) ;
if ( ret )
return ret ;
/* Theoretically there's a race here -- the battery could be
removed immediately after we check whether it ' s present , and
then we query for some other property of the now - absent battery .
It doesn ' t matter though - - the EC will return the last - known
information , and it ' s as if we just ran that _little_ bit faster
and managed to read it out before the battery went away . */
2009-06-30 10:16:17 +04:00
if ( ! ( ec_byte & ( BAT_STAT_PRESENT | BAT_STAT_TRICKLE ) ) & &
psp ! = POWER_SUPPLY_PROP_PRESENT )
2007-05-04 00:51:18 +04:00
return - ENODEV ;
switch ( psp ) {
case POWER_SUPPLY_PROP_STATUS :
2008-05-03 00:41:59 +04:00
ret = olpc_bat_get_status ( val , ec_byte ) ;
if ( ret )
return ret ;
break ;
2009-07-02 17:45:18 +04:00
case POWER_SUPPLY_PROP_CHARGE_TYPE :
if ( ec_byte & BAT_STAT_TRICKLE )
val - > intval = POWER_SUPPLY_CHARGE_TYPE_TRICKLE ;
else if ( ec_byte & BAT_STAT_CHARGING )
val - > intval = POWER_SUPPLY_CHARGE_TYPE_FAST ;
else
val - > intval = POWER_SUPPLY_CHARGE_TYPE_NONE ;
break ;
2007-05-04 00:51:18 +04:00
case POWER_SUPPLY_PROP_PRESENT :
2009-06-30 10:16:17 +04:00
val - > intval = ! ! ( ec_byte & ( BAT_STAT_PRESENT |
BAT_STAT_TRICKLE ) ) ;
2007-05-04 00:51:18 +04:00
break ;
case POWER_SUPPLY_PROP_HEALTH :
if ( ec_byte & BAT_STAT_DESTROY )
val - > intval = POWER_SUPPLY_HEALTH_DEAD ;
else {
2008-05-03 00:41:59 +04:00
ret = olpc_bat_get_health ( val ) ;
2007-05-04 00:51:18 +04:00
if ( ret )
return ret ;
}
break ;
case POWER_SUPPLY_PROP_MANUFACTURER :
2008-05-03 00:41:59 +04:00
ret = olpc_bat_get_mfr ( val ) ;
2007-05-04 00:51:18 +04:00
if ( ret )
return ret ;
break ;
case POWER_SUPPLY_PROP_TECHNOLOGY :
2008-05-03 00:41:59 +04:00
ret = olpc_bat_get_tech ( val ) ;
2007-05-04 00:51:18 +04:00
if ( ret )
return ret ;
break ;
case POWER_SUPPLY_PROP_VOLTAGE_AVG :
2010-12-11 01:05:21 +03:00
case POWER_SUPPLY_PROP_VOLTAGE_NOW :
2007-05-04 00:51:18 +04:00
ret = olpc_ec_cmd ( EC_BAT_VOLTAGE , NULL , 0 , ( void * ) & ec_word , 2 ) ;
if ( ret )
return ret ;
2010-09-25 22:19:26 +04:00
val - > intval = ( s16 ) be16_to_cpu ( ec_word ) * 9760L / 32 ;
2007-05-04 00:51:18 +04:00
break ;
case POWER_SUPPLY_PROP_CURRENT_AVG :
2010-12-11 01:05:21 +03:00
case POWER_SUPPLY_PROP_CURRENT_NOW :
2007-05-04 00:51:18 +04:00
ret = olpc_ec_cmd ( EC_BAT_CURRENT , NULL , 0 , ( void * ) & ec_word , 2 ) ;
if ( ret )
return ret ;
2010-09-25 22:19:26 +04:00
val - > intval = ( s16 ) be16_to_cpu ( ec_word ) * 15625L / 120 ;
2007-05-04 00:51:18 +04:00
break ;
case POWER_SUPPLY_PROP_CAPACITY :
ret = olpc_ec_cmd ( EC_BAT_SOC , NULL , 0 , & ec_byte , 1 ) ;
if ( ret )
return ret ;
val - > intval = ec_byte ;
break ;
2009-06-30 10:13:01 +04:00
case POWER_SUPPLY_PROP_CAPACITY_LEVEL :
if ( ec_byte & BAT_STAT_FULL )
val - > intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL ;
else if ( ec_byte & BAT_STAT_LOW )
val - > intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW ;
else
val - > intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL ;
break ;
2010-12-11 01:05:19 +03:00
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN :
ret = olpc_bat_get_charge_full_design ( val ) ;
if ( ret )
return ret ;
break ;
2010-12-11 01:05:20 +03:00
case POWER_SUPPLY_PROP_CHARGE_NOW :
ret = olpc_bat_get_charge_now ( val ) ;
if ( ret )
return ret ;
break ;
2007-05-04 00:51:18 +04:00
case POWER_SUPPLY_PROP_TEMP :
ret = olpc_ec_cmd ( EC_BAT_TEMP , NULL , 0 , ( void * ) & ec_word , 2 ) ;
if ( ret )
return ret ;
2008-10-16 09:01:23 +04:00
2010-09-25 22:19:26 +04:00
val - > intval = ( s16 ) be16_to_cpu ( ec_word ) * 100 / 256 ;
2007-05-04 00:51:18 +04:00
break ;
case POWER_SUPPLY_PROP_TEMP_AMBIENT :
ret = olpc_ec_cmd ( EC_AMB_TEMP , NULL , 0 , ( void * ) & ec_word , 2 ) ;
if ( ret )
return ret ;
2008-10-16 09:01:23 +04:00
val - > intval = ( int ) be16_to_cpu ( ec_word ) * 100 / 256 ;
2007-05-04 00:51:18 +04:00
break ;
2008-05-13 05:46:29 +04:00
case POWER_SUPPLY_PROP_CHARGE_COUNTER :
ret = olpc_ec_cmd ( EC_BAT_ACR , NULL , 0 , ( void * ) & ec_word , 2 ) ;
if ( ret )
return ret ;
2010-09-25 22:19:26 +04:00
val - > intval = ( s16 ) be16_to_cpu ( ec_word ) * 6250 / 15 ;
2008-05-13 05:46:29 +04:00
break ;
2008-05-04 09:31:42 +04:00
case POWER_SUPPLY_PROP_SERIAL_NUMBER :
ret = olpc_ec_cmd ( EC_BAT_SERIAL , NULL , 0 , ( void * ) & ser_buf , 8 ) ;
if ( ret )
return ret ;
sprintf ( bat_serial , " %016llx " , ( long long ) be64_to_cpu ( ser_buf ) ) ;
val - > strval = bat_serial ;
break ;
2012-07-16 01:43:25 +04:00
case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN :
ret = olpc_bat_get_voltage_max_design ( val ) ;
if ( ret )
return ret ;
break ;
2007-05-04 00:51:18 +04:00
default :
ret = - EINVAL ;
break ;
}
return ret ;
}
2010-12-29 22:12:01 +03:00
static enum power_supply_property olpc_xo1_bat_props [ ] = {
2007-05-04 00:51:18 +04:00
POWER_SUPPLY_PROP_STATUS ,
2009-07-02 17:45:18 +04:00
POWER_SUPPLY_PROP_CHARGE_TYPE ,
2007-05-04 00:51:18 +04:00
POWER_SUPPLY_PROP_PRESENT ,
POWER_SUPPLY_PROP_HEALTH ,
POWER_SUPPLY_PROP_TECHNOLOGY ,
POWER_SUPPLY_PROP_VOLTAGE_AVG ,
2010-12-11 01:05:21 +03:00
POWER_SUPPLY_PROP_VOLTAGE_NOW ,
2007-05-04 00:51:18 +04:00
POWER_SUPPLY_PROP_CURRENT_AVG ,
2010-12-11 01:05:21 +03:00
POWER_SUPPLY_PROP_CURRENT_NOW ,
2007-05-04 00:51:18 +04:00
POWER_SUPPLY_PROP_CAPACITY ,
2009-06-30 10:13:01 +04:00
POWER_SUPPLY_PROP_CAPACITY_LEVEL ,
2010-12-11 01:05:19 +03:00
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN ,
2010-12-11 01:05:20 +03:00
POWER_SUPPLY_PROP_CHARGE_NOW ,
2007-05-04 00:51:18 +04:00
POWER_SUPPLY_PROP_TEMP ,
POWER_SUPPLY_PROP_TEMP_AMBIENT ,
POWER_SUPPLY_PROP_MANUFACTURER ,
2008-05-04 09:31:42 +04:00
POWER_SUPPLY_PROP_SERIAL_NUMBER ,
2008-05-13 05:46:29 +04:00
POWER_SUPPLY_PROP_CHARGE_COUNTER ,
2012-07-16 01:43:25 +04:00
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ,
2007-05-04 00:51:18 +04:00
} ;
2010-12-29 22:12:01 +03:00
/* XO-1.5 does not have ambient temperature property */
static enum power_supply_property olpc_xo15_bat_props [ ] = {
POWER_SUPPLY_PROP_STATUS ,
POWER_SUPPLY_PROP_CHARGE_TYPE ,
POWER_SUPPLY_PROP_PRESENT ,
POWER_SUPPLY_PROP_HEALTH ,
POWER_SUPPLY_PROP_TECHNOLOGY ,
POWER_SUPPLY_PROP_VOLTAGE_AVG ,
2011-01-13 01:23:23 +03:00
POWER_SUPPLY_PROP_VOLTAGE_NOW ,
2010-12-29 22:12:01 +03:00
POWER_SUPPLY_PROP_CURRENT_AVG ,
2011-01-13 01:23:23 +03:00
POWER_SUPPLY_PROP_CURRENT_NOW ,
2010-12-29 22:12:01 +03:00
POWER_SUPPLY_PROP_CAPACITY ,
POWER_SUPPLY_PROP_CAPACITY_LEVEL ,
2011-01-13 01:23:23 +03:00
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN ,
POWER_SUPPLY_PROP_CHARGE_NOW ,
2010-12-29 22:12:01 +03:00
POWER_SUPPLY_PROP_TEMP ,
POWER_SUPPLY_PROP_MANUFACTURER ,
POWER_SUPPLY_PROP_SERIAL_NUMBER ,
POWER_SUPPLY_PROP_CHARGE_COUNTER ,
2012-07-16 01:43:25 +04:00
POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN ,
2010-12-29 22:12:01 +03:00
} ;
2008-05-03 00:41:58 +04:00
/* EEPROM reading goes completely around the power_supply API, sadly */
# define EEPROM_START 0x20
# define EEPROM_END 0x80
# define EEPROM_SIZE (EEPROM_END - EEPROM_START)
2010-05-13 05:28:57 +04:00
static ssize_t olpc_bat_eeprom_read ( struct file * filp , struct kobject * kobj ,
2008-05-03 00:41:58 +04:00
struct bin_attribute * attr , char * buf , loff_t off , size_t count )
{
uint8_t ec_byte ;
2009-06-30 10:14:00 +04:00
int ret ;
int i ;
2008-05-03 00:41:58 +04:00
if ( off > = EEPROM_SIZE )
return 0 ;
if ( off + count > EEPROM_SIZE )
count = EEPROM_SIZE - off ;
2009-06-30 10:14:00 +04:00
for ( i = 0 ; i < count ; i + + ) {
ec_byte = EEPROM_START + off + i ;
ret = olpc_ec_cmd ( EC_BAT_EEPROM , & ec_byte , 1 , & buf [ i ] , 1 ) ;
2008-05-03 00:41:58 +04:00
if ( ret ) {
2009-06-30 10:14:00 +04:00
pr_err ( " olpc-battery: "
" EC_BAT_EEPROM cmd @ 0x%x failed - %d! \n " ,
ec_byte , ret ) ;
2008-05-03 00:41:58 +04:00
return - EIO ;
}
}
return count ;
}
static struct bin_attribute olpc_bat_eeprom = {
. attr = {
. name = " eeprom " ,
. mode = S_IRUGO ,
} ,
. size = 0 ,
. read = olpc_bat_eeprom_read ,
} ;
2009-06-30 10:15:26 +04:00
/* Allow userspace to see the specific error value pulled from the EC */
static ssize_t olpc_bat_error_read ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
uint8_t ec_byte ;
ssize_t ret ;
ret = olpc_ec_cmd ( EC_BAT_ERRCODE , NULL , 0 , & ec_byte , 1 ) ;
if ( ret < 0 )
return ret ;
return sprintf ( buf , " %d \n " , ec_byte ) ;
}
static struct device_attribute olpc_bat_error = {
. attr = {
. name = " error " ,
. mode = S_IRUGO ,
} ,
. show = olpc_bat_error_read ,
} ;
2007-05-04 00:51:18 +04:00
/*********************************************************************
* Initialisation
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct power_supply olpc_bat = {
2011-08-11 00:45:36 +04:00
. name = " olpc-battery " ,
2007-05-04 00:51:18 +04:00
. get_property = olpc_bat_get_property ,
. use_for_apm = 1 ,
} ;
2011-08-11 00:46:02 +04:00
static int olpc_battery_suspend ( struct platform_device * pdev ,
pm_message_t state )
{
if ( device_may_wakeup ( olpc_ac . dev ) )
olpc_ec_wakeup_set ( EC_SCI_SRC_ACPWR ) ;
else
olpc_ec_wakeup_clear ( EC_SCI_SRC_ACPWR ) ;
if ( device_may_wakeup ( olpc_bat . dev ) )
olpc_ec_wakeup_set ( EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
| EC_SCI_SRC_BATERR ) ;
else
olpc_ec_wakeup_clear ( EC_SCI_SRC_BATTERY | EC_SCI_SRC_BATSOC
| EC_SCI_SRC_BATERR ) ;
return 0 ;
}
2012-11-19 22:22:23 +04:00
static int olpc_battery_probe ( struct platform_device * pdev )
2007-05-04 00:51:18 +04:00
{
2011-08-11 00:45:36 +04:00
int ret ;
2007-05-04 00:51:18 +04:00
uint8_t status ;
2008-05-03 00:41:59 +04:00
/*
* We ' ve seen a number of EC protocol changes ; this driver requires
* the latest EC protocol , supported by 0x44 and above .
*/
if ( olpc_platform_info . ecver < 0x44 ) {
printk ( KERN_NOTICE " OLPC EC version 0x%02x too old for "
" battery driver. \n " , olpc_platform_info . ecver ) ;
2007-05-04 00:51:18 +04:00
return - ENXIO ;
}
ret = olpc_ec_cmd ( EC_BAT_STATUS , NULL , 0 , & status , 1 ) ;
if ( ret )
return ret ;
/* Ignore the status. It doesn't actually matter */
2011-08-11 00:45:36 +04:00
ret = power_supply_register ( & pdev - > dev , & olpc_ac ) ;
2007-05-04 00:51:18 +04:00
if ( ret )
2011-08-11 00:45:36 +04:00
return ret ;
2007-05-04 00:51:18 +04:00
2010-12-29 22:12:01 +03:00
if ( olpc_board_at_least ( olpc_board_pre ( 0xd0 ) ) ) { /* XO-1.5 */
olpc_bat . properties = olpc_xo15_bat_props ;
olpc_bat . num_properties = ARRAY_SIZE ( olpc_xo15_bat_props ) ;
} else { /* XO-1 */
olpc_bat . properties = olpc_xo1_bat_props ;
olpc_bat . num_properties = ARRAY_SIZE ( olpc_xo1_bat_props ) ;
}
2007-05-04 00:51:18 +04:00
2011-08-11 00:45:36 +04:00
ret = power_supply_register ( & pdev - > dev , & olpc_bat ) ;
2007-05-04 00:51:18 +04:00
if ( ret )
goto battery_failed ;
2008-05-03 00:41:58 +04:00
ret = device_create_bin_file ( olpc_bat . dev , & olpc_bat_eeprom ) ;
if ( ret )
goto eeprom_failed ;
2009-06-30 10:15:26 +04:00
ret = device_create_file ( olpc_bat . dev , & olpc_bat_error ) ;
if ( ret )
goto error_failed ;
2011-08-11 00:46:02 +04:00
if ( olpc_ec_wakeup_available ( ) ) {
device_set_wakeup_capable ( olpc_ac . dev , true ) ;
device_set_wakeup_capable ( olpc_bat . dev , true ) ;
}
2011-08-11 00:45:36 +04:00
return 0 ;
2007-05-04 00:51:18 +04:00
2009-06-30 10:15:26 +04:00
error_failed :
device_remove_bin_file ( olpc_bat . dev , & olpc_bat_eeprom ) ;
2008-05-03 00:41:58 +04:00
eeprom_failed :
power_supply_unregister ( & olpc_bat ) ;
2007-05-04 00:51:18 +04:00
battery_failed :
power_supply_unregister ( & olpc_ac ) ;
return ret ;
}
2012-11-19 22:26:07 +04:00
static int olpc_battery_remove ( struct platform_device * pdev )
2007-05-04 00:51:18 +04:00
{
2009-06-30 10:15:26 +04:00
device_remove_file ( olpc_bat . dev , & olpc_bat_error ) ;
2008-05-03 00:41:58 +04:00
device_remove_bin_file ( olpc_bat . dev , & olpc_bat_eeprom ) ;
2007-05-04 00:51:18 +04:00
power_supply_unregister ( & olpc_bat ) ;
power_supply_unregister ( & olpc_ac ) ;
2011-08-11 00:45:36 +04:00
return 0 ;
2007-05-04 00:51:18 +04:00
}
2012-12-22 03:04:54 +04:00
static const struct of_device_id olpc_battery_ids [ ] = {
2011-08-11 00:45:36 +04:00
{ . compatible = " olpc,xo1-battery " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , olpc_battery_ids ) ;
olpc_battery: Fix section mismatch noise
This patch fixes the following noise (by renaming _drv to _driver):
WARNING: drivers/power/olpc_battery.o(.data+0x100): Section mismatch in reference from the variable olpc_battery_drv to the function .devinit.text:olpc_battery_probe()
The variable olpc_battery_drv references
the function __devinit olpc_battery_probe()
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
WARNING: drivers/power/olpc_battery.o(.data+0x104): Section mismatch in reference from the variable olpc_battery_drv to the function .devexit.text:olpc_battery_remove()
The variable olpc_battery_drv references
the function __devexit olpc_battery_remove()
If the reference is valid then annotate the
variable with __exit* (see linux/init.h) or name the variable:
*driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
WARNING: drivers/power/olpc_battery.o(.data+0x128): Section mismatch in reference from the variable olpc_battery_drv to the variable .devinit.rodata:olpc_battery_ids
The variable olpc_battery_drv references
the variable __devinitconst olpc_battery_ids
If the reference is valid then annotate the
variable with __init* or __refdata (see linux/init.h) or name the variable:
*driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console
Signed-off-by: Anton Vorontsov <cbouatmailru@gmail.com>
2011-11-24 22:49:07 +04:00
static struct platform_driver olpc_battery_driver = {
2011-08-11 00:45:36 +04:00
. driver = {
. name = " olpc-battery " ,
. owner = THIS_MODULE ,
. of_match_table = olpc_battery_ids ,
} ,
. probe = olpc_battery_probe ,
2012-11-19 22:20:40 +04:00
. remove = olpc_battery_remove ,
2011-08-11 00:46:02 +04:00
. suspend = olpc_battery_suspend ,
2011-08-11 00:45:36 +04:00
} ;
2011-11-26 08:01:10 +04:00
module_platform_driver ( olpc_battery_driver ) ;
2007-05-04 00:51:18 +04:00
MODULE_AUTHOR ( " David Woodhouse <dwmw2@infradead.org> " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Battery driver for One Laptop Per Child 'XO' machine " ) ;