@ -2344,6 +2344,50 @@ static int ab8500_fg_init_hw_registers(struct ab8500_fg *di)
dev_err ( di - > dev , " BattOk init write failed. \n " ) ;
goto out ;
}
if ( ( ( is_ab8505 ( di - > parent ) | | is_ab9540 ( di - > parent ) ) & &
abx500_get_chip_id ( di - > dev ) > = AB8500_CUT2P0 )
| | is_ab8540 ( di - > parent ) ) {
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_MAX_TIME_REG , di - > bm - > fg_params - > pcut_max_time ) ;
if ( ret ) {
dev_err ( di - > dev , " %s write failed AB8505_RTC_PCUT_MAX_TIME_REG \n " , __func__ ) ;
goto out ;
} ;
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_FLAG_TIME_REG , di - > bm - > fg_params - > pcut_flag_time ) ;
if ( ret ) {
dev_err ( di - > dev , " %s write failed AB8505_RTC_PCUT_FLAG_TIME_REG \n " , __func__ ) ;
goto out ;
} ;
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_RESTART_REG , di - > bm - > fg_params - > pcut_max_restart ) ;
if ( ret ) {
dev_err ( di - > dev , " %s write failed AB8505_RTC_PCUT_RESTART_REG \n " , __func__ ) ;
goto out ;
} ;
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_DEBOUNCE_REG , di - > bm - > fg_params - > pcut_debounce_time ) ;
if ( ret ) {
dev_err ( di - > dev , " %s write failed AB8505_RTC_PCUT_DEBOUNCE_REG \n " , __func__ ) ;
goto out ;
} ;
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_CTL_STATUS_REG , di - > bm - > fg_params - > pcut_enable ) ;
if ( ret ) {
dev_err ( di - > dev , " %s write failed AB8505_RTC_PCUT_CTL_STATUS_REG \n " , __func__ ) ;
goto out ;
} ;
}
out :
return ret ;
}
@ -2546,6 +2590,428 @@ static int ab8500_fg_sysfs_init(struct ab8500_fg *di)
return ret ;
}
static ssize_t ab8505_powercut_flagtime_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_FLAG_TIME_REG , & reg_value ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to read AB8505_RTC_PCUT_FLAG_TIME_REG \n " ) ;
goto fail ;
}
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( reg_value & 0x7F ) ) ;
fail :
return ret ;
}
static ssize_t ab8505_powercut_flagtime_write ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
int ret ;
long unsigned reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
reg_value = simple_strtoul ( buf , NULL , 10 ) ;
if ( reg_value > 0x7F ) {
dev_err ( dev , " Incorrect parameter, echo 0 (1.98s) - 127 (15.625ms) for flagtime \n " ) ;
goto fail ;
}
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_FLAG_TIME_REG , ( u8 ) reg_value ) ;
if ( ret < 0 )
dev_err ( dev , " Failed to set AB8505_RTC_PCUT_FLAG_TIME_REG \n " ) ;
fail :
return count ;
}
static ssize_t ab8505_powercut_maxtime_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_MAX_TIME_REG , & reg_value ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to read AB8505_RTC_PCUT_MAX_TIME_REG \n " ) ;
goto fail ;
}
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( reg_value & 0x7F ) ) ;
fail :
return ret ;
}
static ssize_t ab8505_powercut_maxtime_write ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
int ret ;
int reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
reg_value = simple_strtoul ( buf , NULL , 10 ) ;
if ( reg_value > 0x7F ) {
dev_err ( dev , " Incorrect parameter, echo 0 (0.0s) - 127 (1.98s) for maxtime \n " ) ;
goto fail ;
}
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_MAX_TIME_REG , ( u8 ) reg_value ) ;
if ( ret < 0 )
dev_err ( dev , " Failed to set AB8505_RTC_PCUT_MAX_TIME_REG \n " ) ;
fail :
return count ;
}
static ssize_t ab8505_powercut_restart_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_RESTART_REG , & reg_value ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to read AB8505_RTC_PCUT_RESTART_REG \n " ) ;
goto fail ;
}
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( reg_value & 0xF ) ) ;
fail :
return ret ;
}
static ssize_t ab8505_powercut_restart_write ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
int ret ;
int reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
reg_value = simple_strtoul ( buf , NULL , 10 ) ;
if ( reg_value > 0xF ) {
dev_err ( dev , " Incorrect parameter, echo 0 - 15 for number of restart \n " ) ;
goto fail ;
}
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_RESTART_REG , ( u8 ) reg_value ) ;
if ( ret < 0 )
dev_err ( dev , " Failed to set AB8505_RTC_PCUT_RESTART_REG \n " ) ;
fail :
return count ;
}
static ssize_t ab8505_powercut_timer_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_TIME_REG , & reg_value ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to read AB8505_RTC_PCUT_TIME_REG \n " ) ;
goto fail ;
}
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( reg_value & 0x7F ) ) ;
fail :
return ret ;
}
static ssize_t ab8505_powercut_restart_counter_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_RESTART_REG , & reg_value ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to read AB8505_RTC_PCUT_RESTART_REG \n " ) ;
goto fail ;
}
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( reg_value & 0xF0 ) > > 4 ) ;
fail :
return ret ;
}
static ssize_t ab8505_powercut_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_CTL_STATUS_REG , & reg_value ) ;
if ( ret < 0 )
goto fail ;
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( reg_value & 0x1 ) ) ;
fail :
return ret ;
}
static ssize_t ab8505_powercut_write ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
int ret ;
int reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
reg_value = simple_strtoul ( buf , NULL , 10 ) ;
if ( reg_value > 0x1 ) {
dev_err ( dev , " Incorrect parameter, echo 0/1 to disable/enable Pcut feature \n " ) ;
goto fail ;
}
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_CTL_STATUS_REG , ( u8 ) reg_value ) ;
if ( ret < 0 )
dev_err ( dev , " Failed to set AB8505_RTC_PCUT_CTL_STATUS_REG \n " ) ;
fail :
return count ;
}
static ssize_t ab8505_powercut_flag_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_CTL_STATUS_REG , & reg_value ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to read AB8505_RTC_PCUT_CTL_STATUS_REG \n " ) ;
goto fail ;
}
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( ( reg_value & 0x10 ) > > 4 ) ) ;
fail :
return ret ;
}
static ssize_t ab8505_powercut_debounce_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_DEBOUNCE_REG , & reg_value ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to read AB8505_RTC_PCUT_DEBOUNCE_REG \n " ) ;
goto fail ;
}
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( reg_value & 0x7 ) ) ;
fail :
return ret ;
}
static ssize_t ab8505_powercut_debounce_write ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
int ret ;
int reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
reg_value = simple_strtoul ( buf , NULL , 10 ) ;
if ( reg_value > 0x7 ) {
dev_err ( dev , " Incorrect parameter, echo 0 to 7 for debounce setting \n " ) ;
goto fail ;
}
ret = abx500_set_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_DEBOUNCE_REG , ( u8 ) reg_value ) ;
if ( ret < 0 )
dev_err ( dev , " Failed to set AB8505_RTC_PCUT_DEBOUNCE_REG \n " ) ;
fail :
return count ;
}
static ssize_t ab8505_powercut_enable_status_read ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 reg_value ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
ret = abx500_get_register_interruptible ( di - > dev , AB8500_RTC ,
AB8505_RTC_PCUT_CTL_STATUS_REG , & reg_value ) ;
if ( ret < 0 ) {
dev_err ( dev , " Failed to read AB8505_RTC_PCUT_CTL_STATUS_REG \n " ) ;
goto fail ;
}
return scnprintf ( buf , PAGE_SIZE , " %d \n " , ( ( reg_value & 0x20 ) > > 5 ) ) ;
fail :
return ret ;
}
static struct device_attribute ab8505_fg_sysfs_psy_attrs [ ] = {
__ATTR ( powercut_flagtime , ( S_IRUGO | S_IWUSR | S_IWGRP ) ,
ab8505_powercut_flagtime_read , ab8505_powercut_flagtime_write ) ,
__ATTR ( powercut_maxtime , ( S_IRUGO | S_IWUSR | S_IWGRP ) ,
ab8505_powercut_maxtime_read , ab8505_powercut_maxtime_write ) ,
__ATTR ( powercut_restart_max , ( S_IRUGO | S_IWUSR | S_IWGRP ) ,
ab8505_powercut_restart_read , ab8505_powercut_restart_write ) ,
__ATTR ( powercut_timer , S_IRUGO , ab8505_powercut_timer_read , NULL ) ,
__ATTR ( powercut_restart_counter , S_IRUGO ,
ab8505_powercut_restart_counter_read , NULL ) ,
__ATTR ( powercut_enable , ( S_IRUGO | S_IWUSR | S_IWGRP ) ,
ab8505_powercut_read , ab8505_powercut_write ) ,
__ATTR ( powercut_flag , S_IRUGO , ab8505_powercut_flag_read , NULL ) ,
__ATTR ( powercut_debounce_time , ( S_IRUGO | S_IWUSR | S_IWGRP ) ,
ab8505_powercut_debounce_read , ab8505_powercut_debounce_write ) ,
__ATTR ( powercut_enable_status , S_IRUGO ,
ab8505_powercut_enable_status_read , NULL ) ,
} ;
static int ab8500_fg_sysfs_psy_create_attrs ( struct device * dev )
{
unsigned int i , j ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
if ( ( ( is_ab8505 ( di - > parent ) | | is_ab9540 ( di - > parent ) ) & &
abx500_get_chip_id ( dev - > parent ) > = AB8500_CUT2P0 )
| | is_ab8540 ( di - > parent ) ) {
for ( j = 0 ; j < ARRAY_SIZE ( ab8505_fg_sysfs_psy_attrs ) ; j + + )
if ( device_create_file ( dev , & ab8505_fg_sysfs_psy_attrs [ j ] ) )
goto sysfs_psy_create_attrs_failed_ab8505 ;
}
return 0 ;
sysfs_psy_create_attrs_failed_ab8505 :
dev_err ( dev , " Failed creating sysfs psy attrs for ab8505. \n " ) ;
while ( j - - )
device_remove_file ( dev , & ab8505_fg_sysfs_psy_attrs [ i ] ) ;
return - EIO ;
}
static void ab8500_fg_sysfs_psy_remove_attrs ( struct device * dev )
{
unsigned int i ;
struct power_supply * psy = dev_get_drvdata ( dev ) ;
struct ab8500_fg * di ;
di = to_ab8500_fg_device_info ( psy ) ;
if ( ( ( is_ab8505 ( di - > parent ) | | is_ab9540 ( di - > parent ) ) & &
abx500_get_chip_id ( dev - > parent ) > = AB8500_CUT2P0 )
| | is_ab8540 ( di - > parent ) ) {
for ( i = 0 ; i < ARRAY_SIZE ( ab8505_fg_sysfs_psy_attrs ) ; i + + )
( void ) device_remove_file ( dev , & ab8505_fg_sysfs_psy_attrs [ i ] ) ;
}
}
/* Exposure to the sysfs interface <<END>> */
# if defined(CONFIG_PM)
@ -2607,6 +3073,7 @@ static int ab8500_fg_remove(struct platform_device *pdev)
ab8500_fg_sysfs_exit ( di ) ;
flush_scheduled_work ( ) ;
ab8500_fg_sysfs_psy_remove_attrs ( di - > fg_psy . dev ) ;
power_supply_unregister ( & di - > fg_psy ) ;
platform_set_drvdata ( pdev , NULL ) ;
return ret ;
@ -2772,6 +3239,13 @@ static int ab8500_fg_probe(struct platform_device *pdev)
goto free_irq ;
}
ret = ab8500_fg_sysfs_psy_create_attrs ( di - > fg_psy . dev ) ;
if ( ret ) {
dev_err ( di - > dev , " failed to create FG psy \n " ) ;
ab8500_fg_sysfs_exit ( di ) ;
goto free_irq ;
}
/* Calibrate the fg first time */
di - > flags . calibrate = true ;
di - > calib_state = AB8500_FG_CALIB_INIT ;