mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 17:18:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
671
drivers/battery/max17048_fuelgauge.c
Normal file
671
drivers/battery/max17048_fuelgauge.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
* max17048_fuelgauge.c
|
||||
* Samsung MAX17048 Fuel Gauge Driver
|
||||
*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
*
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/battery/sec_fuelgauge.h>
|
||||
#include <linux/sec_batt.h>
|
||||
|
||||
#if 0
|
||||
static int max17048_write_reg(struct i2c_client *client, int reg, u8 value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, reg, value);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int max17048_read_reg(struct i2c_client *client, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max17048_read_word(struct i2c_client *client, int reg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_word_data(client, reg);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max17048_write_word(struct i2c_client *client, int reg, u16 buf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_word_data(client, reg, buf);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void max17048_reset(struct i2c_client *client)
|
||||
{
|
||||
u16 mode, reset_cmd;
|
||||
|
||||
mode = max17048_read_word(client, MAX17048_MODE_MSB);
|
||||
|
||||
mode = swab16(mode);
|
||||
reset_cmd = swab16(mode | 0x4000);
|
||||
|
||||
i2c_smbus_write_word_data(client, MAX17048_MODE_MSB, reset_cmd);
|
||||
|
||||
msleep(300);
|
||||
}
|
||||
|
||||
static int max17048_get_vcell(struct i2c_client *client)
|
||||
{
|
||||
u32 vcell;
|
||||
u16 w_data;
|
||||
u32 temp;
|
||||
|
||||
temp = max17048_read_word(client, MAX17048_VCELL_MSB);
|
||||
|
||||
w_data = swab16(temp);
|
||||
|
||||
temp = ((w_data & 0xFFF0) >> 4) * 1250;
|
||||
vcell = temp / 1000;
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s : vcell (%d)\n", __func__, vcell);
|
||||
|
||||
return vcell;
|
||||
}
|
||||
|
||||
static int max17048_get_avg_vcell(struct i2c_client *client)
|
||||
{
|
||||
u32 vcell_data = 0;
|
||||
u32 vcell_max = 0;
|
||||
u32 vcell_min = 0;
|
||||
u32 vcell_total = 0;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < AVER_SAMPLE_CNT; i++) {
|
||||
vcell_data = max17048_get_vcell(client);
|
||||
|
||||
if (i != 0) {
|
||||
if (vcell_data > vcell_max)
|
||||
vcell_max = vcell_data;
|
||||
else if (vcell_data < vcell_min)
|
||||
vcell_min = vcell_data;
|
||||
} else {
|
||||
vcell_max = vcell_data;
|
||||
vcell_min = vcell_data;
|
||||
}
|
||||
vcell_total += vcell_data;
|
||||
}
|
||||
|
||||
return (vcell_total - vcell_max - vcell_min) / (AVER_SAMPLE_CNT-2);
|
||||
}
|
||||
|
||||
static int max17048_get_ocv(struct i2c_client *client)
|
||||
{
|
||||
u32 ocv;
|
||||
u16 w_data;
|
||||
u32 temp;
|
||||
u16 cmd;
|
||||
|
||||
cmd = swab16(0x4A57);
|
||||
max17048_write_word(client, 0x3E, cmd);
|
||||
|
||||
temp = max17048_read_word(client, MAX17048_OCV_MSB);
|
||||
|
||||
w_data = swab16(temp);
|
||||
|
||||
temp = ((w_data & 0xFFF0) >> 4) * 1250;
|
||||
ocv = temp / 1000;
|
||||
|
||||
cmd = swab16(0x0000);
|
||||
max17048_write_word(client, 0x3E, cmd);
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s : ocv (%d)\n", __func__, ocv);
|
||||
|
||||
return ocv;
|
||||
}
|
||||
|
||||
/* soc should be 0.01% unit */
|
||||
static int max17048_get_soc(struct i2c_client *client)
|
||||
{
|
||||
struct sec_fuelgauge_info *fuelgauge =
|
||||
i2c_get_clientdata(client);
|
||||
u8 data[2] = {0, 0};
|
||||
int temp, soc;
|
||||
u64 psoc64 = 0;
|
||||
u64 temp64;
|
||||
u32 divisor = 10000000;
|
||||
|
||||
temp = max17048_read_word(client, MAX17048_SOC_MSB);
|
||||
|
||||
if (get_battery_data(fuelgauge).is_using_model_data) {
|
||||
/* [ TempSOC = ((SOC1 * 256) + SOC2) * 0.001953125 ] */
|
||||
temp64 = swab16(temp);
|
||||
psoc64 = temp64 * 1953125;
|
||||
psoc64 = div_u64(psoc64, divisor);
|
||||
soc = psoc64 & 0xffff;
|
||||
} else {
|
||||
data[0] = temp & 0xff;
|
||||
data[1] = (temp & 0xff00) >> 8;
|
||||
|
||||
soc = (data[0] * 100) + (data[1] * 100 / 256);
|
||||
}
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s : raw capacity (%d), data(0x%04x)\n",
|
||||
__func__, soc, (data[0]<<8) | data[1]);
|
||||
|
||||
return soc;
|
||||
}
|
||||
|
||||
static int max17048_get_current(struct i2c_client *client)
|
||||
{
|
||||
union power_supply_propval value;
|
||||
|
||||
psy_do_property("sec-charger", get,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW, value);
|
||||
|
||||
return value.intval;
|
||||
}
|
||||
|
||||
#define DISCHARGE_SAMPLE_CNT 5
|
||||
static int discharge_cnt=0;
|
||||
static int all_vcell[5] = {0,};
|
||||
|
||||
/* if ret < 0, discharge */
|
||||
static int sec_bat_check_discharge(int vcell)
|
||||
{
|
||||
int i, cnt, ret = 0;
|
||||
|
||||
all_vcell[discharge_cnt++] = vcell;
|
||||
if (discharge_cnt >= DISCHARGE_SAMPLE_CNT)
|
||||
discharge_cnt = 0;
|
||||
|
||||
cnt = discharge_cnt;
|
||||
|
||||
/* check after last value is set */
|
||||
if (all_vcell[cnt] == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < DISCHARGE_SAMPLE_CNT; i++) {
|
||||
if (cnt == i)
|
||||
continue;
|
||||
if (all_vcell[cnt] > all_vcell[i])
|
||||
ret--;
|
||||
else
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* judge power off or not by current_avg */
|
||||
static int max17048_get_current_average(struct i2c_client *client)
|
||||
{
|
||||
union power_supply_propval value_bat;
|
||||
union power_supply_propval value_chg;
|
||||
int vcell, soc, curr_avg;
|
||||
int check_discharge;
|
||||
|
||||
psy_do_property("sec-charger", get,
|
||||
POWER_SUPPLY_PROP_CURRENT_NOW, value_chg);
|
||||
psy_do_property("battery", get,
|
||||
POWER_SUPPLY_PROP_HEALTH, value_bat);
|
||||
vcell = max17048_get_vcell(client);
|
||||
soc = max17048_get_soc(client) / 100;
|
||||
check_discharge = sec_bat_check_discharge(vcell);
|
||||
|
||||
/* if 0% && under 3.4v && low power charging(1000mA), power off */
|
||||
if (!lpcharge && (soc <= 0) && (vcell < 3400) &&
|
||||
(check_discharge < 0) &&
|
||||
(((value_bat.intval == POWER_SUPPLY_HEALTH_OVERHEAT) ||
|
||||
(value_bat.intval == POWER_SUPPLY_HEALTH_COLD)))) {
|
||||
pr_info("%s: SOC(%d), Vnow(%d), Inow(%d)\n",
|
||||
__func__, soc, vcell, value_chg.intval);
|
||||
curr_avg = -1;
|
||||
} else {
|
||||
curr_avg = value_chg.intval;
|
||||
}
|
||||
|
||||
return curr_avg;
|
||||
}
|
||||
|
||||
void sec_bat_reset_discharge(struct i2c_client *client)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < DISCHARGE_SAMPLE_CNT ; i++)
|
||||
all_vcell[i] = 0;
|
||||
discharge_cnt = 0;
|
||||
}
|
||||
|
||||
static void max17048_get_version(struct i2c_client *client)
|
||||
{
|
||||
u16 w_data;
|
||||
int temp;
|
||||
|
||||
temp = max17048_read_word(client, MAX17048_VER_MSB);
|
||||
|
||||
w_data = swab16(temp);
|
||||
|
||||
dev_info(&client->dev,
|
||||
"MAX17048 Fuel-Gauge Ver 0x%04x\n", w_data);
|
||||
}
|
||||
|
||||
static u16 max17048_get_rcomp(struct i2c_client *client)
|
||||
{
|
||||
u16 w_data;
|
||||
int temp;
|
||||
|
||||
temp = max17048_read_word(client, MAX17048_RCOMP_MSB);
|
||||
|
||||
w_data = swab16(temp);
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s : current rcomp = 0x%04x\n",
|
||||
__func__, w_data);
|
||||
|
||||
return w_data;
|
||||
}
|
||||
|
||||
static void max17048_set_rcomp(struct i2c_client *client, u16 new_rcomp)
|
||||
{
|
||||
i2c_smbus_write_word_data(client,
|
||||
MAX17048_RCOMP_MSB, swab16(new_rcomp));
|
||||
}
|
||||
|
||||
static void max17048_rcomp_update(struct i2c_client *client, int temp)
|
||||
{
|
||||
struct sec_fuelgauge_info *fuelgauge =
|
||||
i2c_get_clientdata(client);
|
||||
union power_supply_propval value;
|
||||
|
||||
int starting_rcomp = 0;
|
||||
int new_rcomp = 0;
|
||||
int rcomp_current = 0;
|
||||
|
||||
rcomp_current = max17048_get_rcomp(client);
|
||||
|
||||
psy_do_property("battery", get,
|
||||
POWER_SUPPLY_PROP_STATUS, value);
|
||||
|
||||
if (value.intval == POWER_SUPPLY_STATUS_CHARGING) /* in charging */
|
||||
starting_rcomp = get_battery_data(fuelgauge).RCOMP_charging;
|
||||
else
|
||||
starting_rcomp = get_battery_data(fuelgauge).RCOMP0;
|
||||
|
||||
if (temp > RCOMP0_TEMP)
|
||||
new_rcomp = starting_rcomp + ((temp - RCOMP0_TEMP) *
|
||||
get_battery_data(fuelgauge).temp_cohot / 1000);
|
||||
else if (temp < RCOMP0_TEMP)
|
||||
new_rcomp = starting_rcomp + ((temp - RCOMP0_TEMP) *
|
||||
get_battery_data(fuelgauge).temp_cocold / 1000);
|
||||
else
|
||||
new_rcomp = starting_rcomp;
|
||||
|
||||
if (new_rcomp > 255)
|
||||
new_rcomp = 255;
|
||||
else if (new_rcomp < 0)
|
||||
new_rcomp = 0;
|
||||
|
||||
new_rcomp <<= 8;
|
||||
new_rcomp &= 0xff00;
|
||||
/* not related to RCOMP */
|
||||
new_rcomp |= (rcomp_current & 0xff);
|
||||
|
||||
if (rcomp_current != new_rcomp) {
|
||||
dev_dbg(&client->dev,
|
||||
"%s : RCOMP 0x%04x -> 0x%04x (0x%02x)\n",
|
||||
__func__, rcomp_current, new_rcomp,
|
||||
new_rcomp >> 8);
|
||||
max17048_set_rcomp(client, new_rcomp);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int max17048_parse_dt(struct device *dev,
|
||||
struct sec_fuelgauge_info *fuelgauge)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret;
|
||||
int value;
|
||||
|
||||
if (np == NULL) {
|
||||
pr_err("%s np NULL\n", __func__);
|
||||
} else {
|
||||
ret = of_property_read_u32(np, "fuelgauge,rcomp0",
|
||||
&value);
|
||||
pr_err("%s value %d\n",
|
||||
__func__, value);
|
||||
get_battery_data(fuelgauge).RCOMP0 = (u8)value;
|
||||
if (ret < 0)
|
||||
pr_err("%s error reading rcomp0 %d\n",
|
||||
__func__, ret);
|
||||
ret = of_property_read_u32(np, "fuelgauge,rcomp_charging",
|
||||
&value);
|
||||
pr_err("%s value %d\n",
|
||||
__func__, value);
|
||||
get_battery_data(fuelgauge).RCOMP_charging = (u8)value;
|
||||
if (ret < 0)
|
||||
pr_err("%s error reading rcomp_charging %d\n",
|
||||
__func__, ret);
|
||||
ret = of_property_read_u32(np, "fuelgauge,temp_cohot",
|
||||
&get_battery_data(fuelgauge).temp_cohot);
|
||||
if (ret < 0)
|
||||
pr_err("%s error reading temp_cohot %d\n",
|
||||
__func__, ret);
|
||||
ret = of_property_read_u32(np, "fuelgauge,temp_cocold",
|
||||
&get_battery_data(fuelgauge).temp_cocold);
|
||||
if (ret < 0)
|
||||
pr_err("%s error reading temp_cocold %d\n",
|
||||
__func__, ret);
|
||||
get_battery_data(fuelgauge).is_using_model_data = of_property_read_bool(np,
|
||||
"fuelgauge,is_using_model_data");
|
||||
ret = of_property_read_string(np, "fuelgauge,type_str",
|
||||
(const char **)&get_battery_data(fuelgauge).type_str);
|
||||
if (ret < 0)
|
||||
pr_err("%s error reading temp_cocold %d\n",
|
||||
__func__, ret);
|
||||
|
||||
pr_info("%s RCOMP0: 0x%x, RCOMP_charging: 0x%x, temp_cohot: %d,"
|
||||
"temp_cocold: %d, is_using_model_data: %d, "
|
||||
"type_str: %s,\n", __func__,
|
||||
get_battery_data(fuelgauge).RCOMP0,
|
||||
get_battery_data(fuelgauge).RCOMP_charging,
|
||||
get_battery_data(fuelgauge).temp_cohot,
|
||||
get_battery_data(fuelgauge).temp_cocold,
|
||||
get_battery_data(fuelgauge).is_using_model_data,
|
||||
get_battery_data(fuelgauge).type_str
|
||||
);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fg_read_regs(struct i2c_client *client, char *str)
|
||||
{
|
||||
int data = 0;
|
||||
u32 addr = 0;
|
||||
|
||||
for (addr = 0x02; addr <= 0x04; addr += 2) {
|
||||
data = max17048_read_word(client, addr);
|
||||
sprintf(str + strlen(str), "0x%04x, ", data);
|
||||
}
|
||||
|
||||
/* "#" considered as new line in application */
|
||||
sprintf(str+strlen(str), "#");
|
||||
|
||||
for (addr = 0x08; addr <= 0x1a; addr += 2) {
|
||||
data = max17048_read_word(client, addr);
|
||||
sprintf(str + strlen(str), "0x%04x, ", data);
|
||||
}
|
||||
}
|
||||
|
||||
bool sec_hal_fg_init(struct i2c_client *client)
|
||||
{
|
||||
#ifdef CONFIG_OF
|
||||
struct sec_fuelgauge_info *fuelgauge =
|
||||
i2c_get_clientdata(client);
|
||||
int error;
|
||||
|
||||
error = max17048_parse_dt(&client->dev, fuelgauge);
|
||||
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"%s : Failed to get max17048 fuel_init\n", __func__);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
pr_info("%s\n", __func__);
|
||||
|
||||
max17048_get_version(client);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_suspend(struct i2c_client *client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_resume(struct i2c_client *client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_fuelalert_init(struct i2c_client *client, int soc)
|
||||
{
|
||||
u16 temp;
|
||||
u8 data;
|
||||
|
||||
temp = max17048_get_rcomp(client);
|
||||
data = 32 - soc; /* set soc for fuel alert */
|
||||
temp &= 0xff00;
|
||||
temp += data;
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s : new rcomp = 0x%04x\n",
|
||||
__func__, temp);
|
||||
|
||||
max17048_set_rcomp(client, temp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_is_fuelalerted(struct i2c_client *client)
|
||||
{
|
||||
u16 temp;
|
||||
|
||||
temp = max17048_get_rcomp(client);
|
||||
|
||||
if (temp & 0x20) /* ALRT is asserted */
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_fuelalert_process(void *irq_data, bool is_fuel_alerted)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_full_charged(struct i2c_client *client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_reset(struct i2c_client *client)
|
||||
{
|
||||
max17048_reset(client);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_get_property(struct i2c_client *client,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
int i, pr_cnt = 1;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
val->intval = 0;
|
||||
break;
|
||||
/* Cell voltage (VCELL, mV) */
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||||
val->intval = max17048_get_vcell(client);
|
||||
break;
|
||||
/* Additional Voltage Information (mV) */
|
||||
case POWER_SUPPLY_PROP_VOLTAGE_AVG:
|
||||
switch (val->intval) {
|
||||
case SEC_BATTEY_VOLTAGE_AVERAGE:
|
||||
val->intval = max17048_get_avg_vcell(client);
|
||||
break;
|
||||
case SEC_BATTEY_VOLTAGE_OCV:
|
||||
val->intval = max17048_get_ocv(client);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
/* Current (mA) */
|
||||
case POWER_SUPPLY_PROP_CURRENT_NOW:
|
||||
val->intval = max17048_get_current(client);
|
||||
break;
|
||||
/* Average Current (mA) */
|
||||
case POWER_SUPPLY_PROP_CURRENT_AVG:
|
||||
val->intval = max17048_get_current_average(client);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_FULL:
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_ENERGY_NOW:
|
||||
break;
|
||||
/* SOC (%) */
|
||||
case POWER_SUPPLY_PROP_CAPACITY:
|
||||
if (val->intval == SEC_FUELGAUGE_CAPACITY_TYPE_RAW) {
|
||||
val->intval = max17048_get_soc(client);
|
||||
} else {
|
||||
val->intval = max17048_get_soc(client) / 10;
|
||||
if (!(pr_cnt++ % 10)) {
|
||||
pr_cnt = 1;
|
||||
for (i = 0x02; i < 0x1C; i++)
|
||||
printk("0x%02x(0x%02x), ",
|
||||
i, max17048_read_reg(client, i));
|
||||
printk("\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* Battery Temperature */
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
/* Target Temperature */
|
||||
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sec_hal_fg_set_property(struct i2c_client *client,
|
||||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
sec_bat_reset_discharge(client);
|
||||
break;
|
||||
/* Battery Temperature */
|
||||
case POWER_SUPPLY_PROP_TEMP:
|
||||
/* Target Temperature */
|
||||
/* temperature is 0.1 degree, should be divide by 10 */
|
||||
max17048_rcomp_update(client, val->intval / 10);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t sec_hal_fg_show_attrs(struct device *dev,
|
||||
const ptrdiff_t offset, char *buf)
|
||||
{
|
||||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
struct sec_fuelgauge_info *fg =
|
||||
container_of(psy, struct sec_fuelgauge_info, psy_fg);
|
||||
int i = 0;
|
||||
char *str = NULL;
|
||||
|
||||
switch (offset) {
|
||||
case FG_DATA:
|
||||
i += scnprintf(buf + i, PAGE_SIZE - i, "%02x%02x\n",
|
||||
fg->reg_data[1], fg->reg_data[0]);
|
||||
break;
|
||||
case FG_REGS:
|
||||
str = kzalloc(sizeof(char)*1024, GFP_KERNEL);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
|
||||
fg_read_regs(fg->client, str);
|
||||
i += scnprintf(buf + i, PAGE_SIZE - i, "%s\n",
|
||||
str);
|
||||
|
||||
kfree(str);
|
||||
break;
|
||||
default:
|
||||
i = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
ssize_t sec_hal_fg_store_attrs(struct device *dev,
|
||||
const ptrdiff_t offset,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct power_supply *psy = dev_get_drvdata(dev);
|
||||
struct sec_fuelgauge_info *fg =
|
||||
container_of(psy, struct sec_fuelgauge_info, psy_fg);
|
||||
int ret = 0;
|
||||
int x = 0;
|
||||
u16 data;
|
||||
|
||||
switch (offset) {
|
||||
case FG_REG:
|
||||
if (sscanf(buf, "%x\n", &x) == 1) {
|
||||
fg->reg_addr = x;
|
||||
data = max17048_read_word(
|
||||
fg->client, fg->reg_addr);
|
||||
fg->reg_data[0] = (data & 0xff00) >> 8;
|
||||
fg->reg_data[1] = (data & 0x00ff);
|
||||
|
||||
dev_dbg(&fg->client->dev,
|
||||
"%s: (read) addr = 0x%x, data = 0x%02x%02x\n",
|
||||
__func__, fg->reg_addr,
|
||||
fg->reg_data[1], fg->reg_data[0]);
|
||||
ret = count;
|
||||
}
|
||||
break;
|
||||
case FG_DATA:
|
||||
if (sscanf(buf, "%x\n", &x) == 1) {
|
||||
dev_dbg(&fg->client->dev,
|
||||
"%s: (write) addr = 0x%x, data = 0x%04x\n",
|
||||
__func__, fg->reg_addr, x);
|
||||
i2c_smbus_write_word_data(fg->client,
|
||||
fg->reg_addr, swab16(x));
|
||||
ret = count;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue