2011-05-27 03:26:04 +04:00
/*
* 1 - wire client / driver for the Maxim / Dallas DS2780 Stand - Alone Fuel Gauge IC
*
* Copyright ( C ) 2010 Indesign , LLC
*
* Author : Clifton Barnes < cabarnes @ indesign - llc . com >
*
* Based on ds2760_battery and ds2782_battery drivers
*
* 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/slab.h>
# include <linux/param.h>
# include <linux/pm.h>
# include <linux/platform_device.h>
# include <linux/power_supply.h>
# include <linux/idr.h>
# include "../w1/w1.h"
# include "../w1/slaves/w1_ds2780.h"
/* Current unit measurement in uA for a 1 milli-ohm sense resistor */
# define DS2780_CURRENT_UNITS 1563
/* Charge unit measurement in uAh for a 1 milli-ohm sense resistor */
# define DS2780_CHARGE_UNITS 6250
/* Number of bytes in user EEPROM space */
# define DS2780_USER_EEPROM_SIZE (DS2780_EEPROM_BLOCK0_END - \
DS2780_EEPROM_BLOCK0_START + 1 )
/* Number of bytes in parameter EEPROM space */
# define DS2780_PARAM_EEPROM_SIZE (DS2780_EEPROM_BLOCK1_END - \
DS2780_EEPROM_BLOCK1_START + 1 )
struct ds2780_device_info {
struct device * dev ;
struct power_supply bat ;
struct device * w1_dev ;
} ;
enum current_types {
CURRENT_NOW ,
CURRENT_AVG ,
} ;
static const char model [ ] = " DS2780 " ;
static const char manufacturer [ ] = " Maxim/Dallas " ;
2011-11-03 00:39:50 +04:00
static inline struct ds2780_device_info *
to_ds2780_device_info ( struct power_supply * psy )
2011-05-27 03:26:04 +04:00
{
return container_of ( psy , struct ds2780_device_info , bat ) ;
}
static inline struct power_supply * to_power_supply ( struct device * dev )
{
return dev_get_drvdata ( dev ) ;
}
2011-11-03 00:39:50 +04:00
static inline int ds2780_battery_io ( struct ds2780_device_info * dev_info ,
char * buf , int addr , size_t count , int io )
2011-05-27 03:26:04 +04:00
{
2012-05-18 09:59:52 +04:00
return w1_ds2780_io ( dev_info - > w1_dev , buf , addr , count , io ) ;
2011-05-27 03:26:04 +04:00
}
2011-11-03 00:39:50 +04:00
static inline int ds2780_read8 ( struct ds2780_device_info * dev_info , u8 * val ,
int addr )
{
return ds2780_battery_io ( dev_info , val , addr , sizeof ( u8 ) , 0 ) ;
2011-05-27 03:26:04 +04:00
}
2011-11-03 00:39:50 +04:00
static int ds2780_read16 ( struct ds2780_device_info * dev_info , s16 * val ,
int addr )
2011-05-27 03:26:04 +04:00
{
int ret ;
u8 raw [ 2 ] ;
2011-11-03 00:39:50 +04:00
ret = ds2780_battery_io ( dev_info , raw , addr , sizeof ( raw ) , 0 ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
* val = ( raw [ 0 ] < < 8 ) | raw [ 1 ] ;
return 0 ;
}
2011-11-03 00:39:50 +04:00
static inline int ds2780_read_block ( struct ds2780_device_info * dev_info ,
u8 * val , int addr , size_t count )
2011-05-27 03:26:04 +04:00
{
2011-11-03 00:39:50 +04:00
return ds2780_battery_io ( dev_info , val , addr , count , 0 ) ;
2011-05-27 03:26:04 +04:00
}
2011-11-03 00:39:50 +04:00
static inline int ds2780_write ( struct ds2780_device_info * dev_info , u8 * val ,
int addr , size_t count )
2011-05-27 03:26:04 +04:00
{
2011-11-03 00:39:50 +04:00
return ds2780_battery_io ( dev_info , val , addr , count , 1 ) ;
2011-05-27 03:26:04 +04:00
}
static inline int ds2780_store_eeprom ( struct device * dev , int addr )
{
return w1_ds2780_eeprom_cmd ( dev , addr , W1_DS2780_COPY_DATA ) ;
}
static inline int ds2780_recall_eeprom ( struct device * dev , int addr )
{
return w1_ds2780_eeprom_cmd ( dev , addr , W1_DS2780_RECALL_DATA ) ;
}
static int ds2780_save_eeprom ( struct ds2780_device_info * dev_info , int reg )
{
int ret ;
ret = ds2780_store_eeprom ( dev_info - > w1_dev , reg ) ;
if ( ret < 0 )
return ret ;
ret = ds2780_recall_eeprom ( dev_info - > w1_dev , reg ) ;
if ( ret < 0 )
return ret ;
return 0 ;
}
/* Set sense resistor value in mhos */
static int ds2780_set_sense_register ( struct ds2780_device_info * dev_info ,
u8 conductance )
{
int ret ;
2011-11-03 00:39:50 +04:00
ret = ds2780_write ( dev_info , & conductance ,
2011-05-27 03:26:04 +04:00
DS2780_RSNSP_REG , sizeof ( u8 ) ) ;
if ( ret < 0 )
return ret ;
return ds2780_save_eeprom ( dev_info , DS2780_RSNSP_REG ) ;
}
/* Get RSGAIN value from 0 to 1.999 in steps of 0.001 */
static int ds2780_get_rsgain_register ( struct ds2780_device_info * dev_info ,
u16 * rsgain )
{
2011-11-03 00:39:50 +04:00
return ds2780_read16 ( dev_info , rsgain , DS2780_RSGAIN_MSB_REG ) ;
2011-05-27 03:26:04 +04:00
}
/* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */
static int ds2780_set_rsgain_register ( struct ds2780_device_info * dev_info ,
u16 rsgain )
{
int ret ;
u8 raw [ ] = { rsgain > > 8 , rsgain & 0xFF } ;
2011-11-03 00:39:50 +04:00
ret = ds2780_write ( dev_info , raw ,
DS2780_RSGAIN_MSB_REG , sizeof ( raw ) ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
return ds2780_save_eeprom ( dev_info , DS2780_RSGAIN_MSB_REG ) ;
}
static int ds2780_get_voltage ( struct ds2780_device_info * dev_info ,
int * voltage_uV )
{
int ret ;
s16 voltage_raw ;
/*
* The voltage value is located in 10 bits across the voltage MSB
* and LSB registers in two ' s compliment form
* Sign bit of the voltage value is in bit 7 of the voltage MSB register
* Bits 9 - 3 of the voltage value are in bits 6 - 0 of the
* voltage MSB register
* Bits 2 - 0 of the voltage value are in bits 7 - 5 of the
* voltage LSB register
*/
2011-11-03 00:39:50 +04:00
ret = ds2780_read16 ( dev_info , & voltage_raw ,
2011-05-27 03:26:04 +04:00
DS2780_VOLT_MSB_REG ) ;
if ( ret < 0 )
return ret ;
/*
* DS2780 reports voltage in units of 4.88 mV , but the battery class
* reports in units of uV , so convert by multiplying by 4880.
*/
* voltage_uV = ( voltage_raw / 32 ) * 4880 ;
return 0 ;
}
static int ds2780_get_temperature ( struct ds2780_device_info * dev_info ,
int * temperature )
{
int ret ;
s16 temperature_raw ;
/*
* The temperature value is located in 10 bits across the temperature
* MSB and LSB registers in two ' s compliment form
* Sign bit of the temperature value is in bit 7 of the temperature
* MSB register
* Bits 9 - 3 of the temperature value are in bits 6 - 0 of the
* temperature MSB register
* Bits 2 - 0 of the temperature value are in bits 7 - 5 of the
* temperature LSB register
*/
2011-11-03 00:39:50 +04:00
ret = ds2780_read16 ( dev_info , & temperature_raw ,
2011-05-27 03:26:04 +04:00
DS2780_TEMP_MSB_REG ) ;
if ( ret < 0 )
return ret ;
/*
* Temperature is measured in units of 0.125 degrees celcius , the
* power_supply class measures temperature in tenths of degrees
* celsius . The temperature value is stored as a 10 bit number , plus
* sign in the upper bits of a 16 bit register .
*/
* temperature = ( ( temperature_raw / 32 ) * 125 ) / 100 ;
return 0 ;
}
static int ds2780_get_current ( struct ds2780_device_info * dev_info ,
enum current_types type , int * current_uA )
{
int ret , sense_res ;
s16 current_raw ;
u8 sense_res_raw , reg_msb ;
/*
* The units of measurement for current are dependent on the value of
* the sense resistor .
*/
2011-11-03 00:39:50 +04:00
ret = ds2780_read8 ( dev_info , & sense_res_raw , DS2780_RSNSP_REG ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
if ( sense_res_raw = = 0 ) {
dev_err ( dev_info - > dev , " sense resistor value is 0 \n " ) ;
2011-11-03 00:39:50 +04:00
return - EINVAL ;
2011-05-27 03:26:04 +04:00
}
sense_res = 1000 / sense_res_raw ;
if ( type = = CURRENT_NOW )
reg_msb = DS2780_CURRENT_MSB_REG ;
else if ( type = = CURRENT_AVG )
reg_msb = DS2780_IAVG_MSB_REG ;
else
return - EINVAL ;
/*
* The current value is located in 16 bits across the current MSB
* and LSB registers in two ' s compliment form
* Sign bit of the current value is in bit 7 of the current MSB register
* Bits 14 - 8 of the current value are in bits 6 - 0 of the current
* MSB register
* Bits 7 - 0 of the current value are in bits 7 - 0 of the current
* LSB register
*/
2011-11-03 00:39:50 +04:00
ret = ds2780_read16 ( dev_info , & current_raw , reg_msb ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
* current_uA = current_raw * ( DS2780_CURRENT_UNITS / sense_res ) ;
return 0 ;
}
static int ds2780_get_accumulated_current ( struct ds2780_device_info * dev_info ,
int * accumulated_current )
{
int ret , sense_res ;
s16 current_raw ;
u8 sense_res_raw ;
/*
* The units of measurement for accumulated current are dependent on
* the value of the sense resistor .
*/
2011-11-03 00:39:50 +04:00
ret = ds2780_read8 ( dev_info , & sense_res_raw , DS2780_RSNSP_REG ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
if ( sense_res_raw = = 0 ) {
dev_err ( dev_info - > dev , " sense resistor value is 0 \n " ) ;
return - ENXIO ;
}
sense_res = 1000 / sense_res_raw ;
/*
* The ACR value is located in 16 bits across the ACR MSB and
* LSB registers
* Bits 15 - 8 of the ACR value are in bits 7 - 0 of the ACR
* MSB register
* Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR
* LSB register
*/
2011-11-03 00:39:50 +04:00
ret = ds2780_read16 ( dev_info , & current_raw , DS2780_ACR_MSB_REG ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
* accumulated_current = current_raw * ( DS2780_CHARGE_UNITS / sense_res ) ;
return 0 ;
}
static int ds2780_get_capacity ( struct ds2780_device_info * dev_info ,
int * capacity )
{
int ret ;
u8 raw ;
2011-11-03 00:39:50 +04:00
ret = ds2780_read8 ( dev_info , & raw , DS2780_RARC_REG ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
* capacity = raw ;
return raw ;
}
static int ds2780_get_status ( struct ds2780_device_info * dev_info , int * status )
{
int ret , current_uA , capacity ;
ret = ds2780_get_current ( dev_info , CURRENT_NOW , & current_uA ) ;
if ( ret < 0 )
return ret ;
ret = ds2780_get_capacity ( dev_info , & capacity ) ;
if ( ret < 0 )
return ret ;
if ( capacity = = 100 )
* status = POWER_SUPPLY_STATUS_FULL ;
else if ( current_uA = = 0 )
* status = POWER_SUPPLY_STATUS_NOT_CHARGING ;
else if ( current_uA < 0 )
* status = POWER_SUPPLY_STATUS_DISCHARGING ;
else
* status = POWER_SUPPLY_STATUS_CHARGING ;
return 0 ;
}
static int ds2780_get_charge_now ( struct ds2780_device_info * dev_info ,
int * charge_now )
{
int ret ;
u16 charge_raw ;
/*
* The RAAC value is located in 16 bits across the RAAC MSB and
* LSB registers
* Bits 15 - 8 of the RAAC value are in bits 7 - 0 of the RAAC
* MSB register
* Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC
* LSB register
*/
2011-11-03 00:39:50 +04:00
ret = ds2780_read16 ( dev_info , & charge_raw , DS2780_RAAC_MSB_REG ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
* charge_now = charge_raw * 1600 ;
return 0 ;
}
static int ds2780_get_control_register ( struct ds2780_device_info * dev_info ,
u8 * control_reg )
{
2011-11-03 00:39:50 +04:00
return ds2780_read8 ( dev_info , control_reg , DS2780_CONTROL_REG ) ;
2011-05-27 03:26:04 +04:00
}
static int ds2780_set_control_register ( struct ds2780_device_info * dev_info ,
u8 control_reg )
{
int ret ;
2011-11-03 00:39:50 +04:00
ret = ds2780_write ( dev_info , & control_reg ,
2011-05-27 03:26:04 +04:00
DS2780_CONTROL_REG , sizeof ( u8 ) ) ;
if ( ret < 0 )
return ret ;
return ds2780_save_eeprom ( dev_info , DS2780_CONTROL_REG ) ;
}
static int ds2780_battery_get_property ( struct power_supply * psy ,
enum power_supply_property psp ,
union power_supply_propval * val )
{
int ret = 0 ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
switch ( psp ) {
case POWER_SUPPLY_PROP_VOLTAGE_NOW :
ret = ds2780_get_voltage ( dev_info , & val - > intval ) ;
break ;
case POWER_SUPPLY_PROP_TEMP :
ret = ds2780_get_temperature ( dev_info , & val - > intval ) ;
break ;
case POWER_SUPPLY_PROP_MODEL_NAME :
val - > strval = model ;
break ;
case POWER_SUPPLY_PROP_MANUFACTURER :
val - > strval = manufacturer ;
break ;
case POWER_SUPPLY_PROP_CURRENT_NOW :
ret = ds2780_get_current ( dev_info , CURRENT_NOW , & val - > intval ) ;
break ;
case POWER_SUPPLY_PROP_CURRENT_AVG :
ret = ds2780_get_current ( dev_info , CURRENT_AVG , & val - > intval ) ;
break ;
case POWER_SUPPLY_PROP_STATUS :
ret = ds2780_get_status ( dev_info , & val - > intval ) ;
break ;
case POWER_SUPPLY_PROP_CAPACITY :
ret = ds2780_get_capacity ( dev_info , & val - > intval ) ;
break ;
case POWER_SUPPLY_PROP_CHARGE_COUNTER :
ret = ds2780_get_accumulated_current ( dev_info , & val - > intval ) ;
break ;
case POWER_SUPPLY_PROP_CHARGE_NOW :
ret = ds2780_get_charge_now ( dev_info , & val - > intval ) ;
break ;
default :
ret = - EINVAL ;
}
return ret ;
}
static enum power_supply_property ds2780_battery_props [ ] = {
POWER_SUPPLY_PROP_STATUS ,
POWER_SUPPLY_PROP_VOLTAGE_NOW ,
POWER_SUPPLY_PROP_TEMP ,
POWER_SUPPLY_PROP_MODEL_NAME ,
POWER_SUPPLY_PROP_MANUFACTURER ,
POWER_SUPPLY_PROP_CURRENT_NOW ,
POWER_SUPPLY_PROP_CURRENT_AVG ,
POWER_SUPPLY_PROP_CAPACITY ,
POWER_SUPPLY_PROP_CHARGE_COUNTER ,
POWER_SUPPLY_PROP_CHARGE_NOW ,
} ;
static ssize_t ds2780_get_pmod_enabled ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 control_reg ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
/* Get power mode */
ret = ds2780_get_control_register ( dev_info , & control_reg ) ;
if ( ret < 0 )
return ret ;
return sprintf ( buf , " %d \n " ,
! ! ( control_reg & DS2780_CONTROL_REG_PMOD ) ) ;
}
static ssize_t ds2780_set_pmod_enabled ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t count )
{
int ret ;
u8 control_reg , new_setting ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
/* Set power mode */
ret = ds2780_get_control_register ( dev_info , & control_reg ) ;
if ( ret < 0 )
return ret ;
ret = kstrtou8 ( buf , 0 , & new_setting ) ;
if ( ret < 0 )
return ret ;
if ( ( new_setting ! = 0 ) & & ( new_setting ! = 1 ) ) {
dev_err ( dev_info - > dev , " Invalid pmod setting (0 or 1) \n " ) ;
return - EINVAL ;
}
if ( new_setting )
control_reg | = DS2780_CONTROL_REG_PMOD ;
else
control_reg & = ~ DS2780_CONTROL_REG_PMOD ;
ret = ds2780_set_control_register ( dev_info , control_reg ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static ssize_t ds2780_get_sense_resistor_value ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 sense_resistor ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
2011-11-03 00:39:50 +04:00
ret = ds2780_read8 ( dev_info , & sense_resistor , DS2780_RSNSP_REG ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
ret = sprintf ( buf , " %d \n " , sense_resistor ) ;
return ret ;
}
static ssize_t ds2780_set_sense_resistor_value ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t count )
{
int ret ;
u8 new_setting ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
ret = kstrtou8 ( buf , 0 , & new_setting ) ;
if ( ret < 0 )
return ret ;
ret = ds2780_set_sense_register ( dev_info , new_setting ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static ssize_t ds2780_get_rsgain_setting ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u16 rsgain ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
ret = ds2780_get_rsgain_register ( dev_info , & rsgain ) ;
if ( ret < 0 )
return ret ;
return sprintf ( buf , " %d \n " , rsgain ) ;
}
static ssize_t ds2780_set_rsgain_setting ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t count )
{
int ret ;
u16 new_setting ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
ret = kstrtou16 ( buf , 0 , & new_setting ) ;
if ( ret < 0 )
return ret ;
/* Gain can only be from 0 to 1.999 in steps of .001 */
if ( new_setting > 1999 ) {
dev_err ( dev_info - > dev , " Invalid rsgain setting (0 - 1999) \n " ) ;
return - EINVAL ;
}
ret = ds2780_set_rsgain_register ( dev_info , new_setting ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static ssize_t ds2780_get_pio_pin ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
int ret ;
u8 sfr ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
2011-11-03 00:39:50 +04:00
ret = ds2780_read8 ( dev_info , & sfr , DS2780_SFR_REG ) ;
2011-05-27 03:26:04 +04:00
if ( ret < 0 )
return ret ;
ret = sprintf ( buf , " %d \n " , sfr & DS2780_SFR_REG_PIOSC ) ;
return ret ;
}
static ssize_t ds2780_set_pio_pin ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t count )
{
int ret ;
u8 new_setting ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
ret = kstrtou8 ( buf , 0 , & new_setting ) ;
if ( ret < 0 )
return ret ;
if ( ( new_setting ! = 0 ) & & ( new_setting ! = 1 ) ) {
dev_err ( dev_info - > dev , " Invalid pio_pin setting (0 or 1) \n " ) ;
return - EINVAL ;
}
2011-11-03 00:39:50 +04:00
ret = ds2780_write ( dev_info , & new_setting ,
2011-05-27 03:26:04 +04:00
DS2780_SFR_REG , sizeof ( u8 ) ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static ssize_t ds2780_read_param_eeprom_bin ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * bin_attr ,
char * buf , loff_t off , size_t count )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
count = min_t ( loff_t , count ,
DS2780_EEPROM_BLOCK1_END -
DS2780_EEPROM_BLOCK1_START + 1 - off ) ;
2011-11-03 00:39:50 +04:00
return ds2780_read_block ( dev_info , buf ,
2011-05-27 03:26:04 +04:00
DS2780_EEPROM_BLOCK1_START + off , count ) ;
}
static ssize_t ds2780_write_param_eeprom_bin ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * bin_attr ,
char * buf , loff_t off , size_t count )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
int ret ;
count = min_t ( loff_t , count ,
DS2780_EEPROM_BLOCK1_END -
DS2780_EEPROM_BLOCK1_START + 1 - off ) ;
2011-11-03 00:39:50 +04:00
ret = ds2780_write ( dev_info , buf ,
2011-05-27 03:26:04 +04:00
DS2780_EEPROM_BLOCK1_START + off , count ) ;
if ( ret < 0 )
return ret ;
ret = ds2780_save_eeprom ( dev_info , DS2780_EEPROM_BLOCK1_START ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static struct bin_attribute ds2780_param_eeprom_bin_attr = {
. attr = {
. name = " param_eeprom " ,
. mode = S_IRUGO | S_IWUSR ,
} ,
. size = DS2780_EEPROM_BLOCK1_END - DS2780_EEPROM_BLOCK1_START + 1 ,
. read = ds2780_read_param_eeprom_bin ,
. write = ds2780_write_param_eeprom_bin ,
} ;
static ssize_t ds2780_read_user_eeprom_bin ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * bin_attr ,
char * buf , loff_t off , size_t count )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
count = min_t ( loff_t , count ,
DS2780_EEPROM_BLOCK0_END -
DS2780_EEPROM_BLOCK0_START + 1 - off ) ;
2011-11-03 00:39:50 +04:00
return ds2780_read_block ( dev_info , buf ,
2011-05-27 03:26:04 +04:00
DS2780_EEPROM_BLOCK0_START + off , count ) ;
}
static ssize_t ds2780_write_user_eeprom_bin ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * bin_attr ,
char * buf , loff_t off , size_t count )
{
struct device * dev = container_of ( kobj , struct device , kobj ) ;
struct power_supply * psy = to_power_supply ( dev ) ;
struct ds2780_device_info * dev_info = to_ds2780_device_info ( psy ) ;
int ret ;
count = min_t ( loff_t , count ,
DS2780_EEPROM_BLOCK0_END -
DS2780_EEPROM_BLOCK0_START + 1 - off ) ;
2011-11-03 00:39:50 +04:00
ret = ds2780_write ( dev_info , buf ,
2011-05-27 03:26:04 +04:00
DS2780_EEPROM_BLOCK0_START + off , count ) ;
if ( ret < 0 )
return ret ;
ret = ds2780_save_eeprom ( dev_info , DS2780_EEPROM_BLOCK0_START ) ;
if ( ret < 0 )
return ret ;
return count ;
}
static struct bin_attribute ds2780_user_eeprom_bin_attr = {
. attr = {
. name = " user_eeprom " ,
. mode = S_IRUGO | S_IWUSR ,
} ,
. size = DS2780_EEPROM_BLOCK0_END - DS2780_EEPROM_BLOCK0_START + 1 ,
. read = ds2780_read_user_eeprom_bin ,
. write = ds2780_write_user_eeprom_bin ,
} ;
static DEVICE_ATTR ( pmod_enabled , S_IRUGO | S_IWUSR , ds2780_get_pmod_enabled ,
ds2780_set_pmod_enabled ) ;
static DEVICE_ATTR ( sense_resistor_value , S_IRUGO | S_IWUSR ,
ds2780_get_sense_resistor_value , ds2780_set_sense_resistor_value ) ;
static DEVICE_ATTR ( rsgain_setting , S_IRUGO | S_IWUSR , ds2780_get_rsgain_setting ,
ds2780_set_rsgain_setting ) ;
static DEVICE_ATTR ( pio_pin , S_IRUGO | S_IWUSR , ds2780_get_pio_pin ,
ds2780_set_pio_pin ) ;
static struct attribute * ds2780_attributes [ ] = {
& dev_attr_pmod_enabled . attr ,
& dev_attr_sense_resistor_value . attr ,
& dev_attr_rsgain_setting . attr ,
& dev_attr_pio_pin . attr ,
NULL
} ;
static const struct attribute_group ds2780_attr_group = {
. attrs = ds2780_attributes ,
} ;
2012-11-19 22:22:23 +04:00
static int ds2780_battery_probe ( struct platform_device * pdev )
2011-05-27 03:26:04 +04:00
{
int ret = 0 ;
struct ds2780_device_info * dev_info ;
dev_info = kzalloc ( sizeof ( * dev_info ) , GFP_KERNEL ) ;
if ( ! dev_info ) {
ret = - ENOMEM ;
goto fail ;
}
platform_set_drvdata ( pdev , dev_info ) ;
dev_info - > dev = & pdev - > dev ;
dev_info - > w1_dev = pdev - > dev . parent ;
dev_info - > bat . name = dev_name ( & pdev - > dev ) ;
dev_info - > bat . type = POWER_SUPPLY_TYPE_BATTERY ;
dev_info - > bat . properties = ds2780_battery_props ;
dev_info - > bat . num_properties = ARRAY_SIZE ( ds2780_battery_props ) ;
dev_info - > bat . get_property = ds2780_battery_get_property ;
ret = power_supply_register ( & pdev - > dev , & dev_info - > bat ) ;
if ( ret ) {
dev_err ( dev_info - > dev , " failed to register battery \n " ) ;
goto fail_free_info ;
}
ret = sysfs_create_group ( & dev_info - > bat . dev - > kobj , & ds2780_attr_group ) ;
if ( ret ) {
dev_err ( dev_info - > dev , " failed to create sysfs group \n " ) ;
goto fail_unregister ;
}
ret = sysfs_create_bin_file ( & dev_info - > bat . dev - > kobj ,
& ds2780_param_eeprom_bin_attr ) ;
if ( ret ) {
dev_err ( dev_info - > dev ,
" failed to create param eeprom bin file " ) ;
goto fail_remove_group ;
}
ret = sysfs_create_bin_file ( & dev_info - > bat . dev - > kobj ,
& ds2780_user_eeprom_bin_attr ) ;
if ( ret ) {
dev_err ( dev_info - > dev ,
" failed to create user eeprom bin file " ) ;
goto fail_remove_bin_file ;
}
return 0 ;
fail_remove_bin_file :
sysfs_remove_bin_file ( & dev_info - > bat . dev - > kobj ,
& ds2780_param_eeprom_bin_attr ) ;
fail_remove_group :
sysfs_remove_group ( & dev_info - > bat . dev - > kobj , & ds2780_attr_group ) ;
fail_unregister :
power_supply_unregister ( & dev_info - > bat ) ;
fail_free_info :
kfree ( dev_info ) ;
fail :
return ret ;
}
2012-11-19 22:26:07 +04:00
static int ds2780_battery_remove ( struct platform_device * pdev )
2011-05-27 03:26:04 +04:00
{
struct ds2780_device_info * dev_info = platform_get_drvdata ( pdev ) ;
/* remove attributes */
sysfs_remove_group ( & dev_info - > bat . dev - > kobj , & ds2780_attr_group ) ;
power_supply_unregister ( & dev_info - > bat ) ;
kfree ( dev_info ) ;
return 0 ;
}
static struct platform_driver ds2780_battery_driver = {
. driver = {
. name = " ds2780-battery " ,
} ,
. probe = ds2780_battery_probe ,
2012-11-19 22:20:40 +04:00
. remove = ds2780_battery_remove ,
2011-05-27 03:26:04 +04:00
} ;
2011-11-26 08:01:10 +04:00
module_platform_driver ( ds2780_battery_driver ) ;
2011-05-27 03:26:04 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Clifton Barnes <cabarnes@indesign-llc.com> " ) ;
MODULE_DESCRIPTION ( " Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver " ) ;
2011-11-26 08:01:10 +04:00
MODULE_ALIAS ( " platform:ds2780-battery " ) ;