blob: e9b5e7520b00d660156825d0527339d88c7e2195 [file] [log] [blame]
/*
* Fuel gauge driver for Maxim 17050
*
* Copyright (C) 2011 Samsung Electronics
* Copyright (C) 2013 Google Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Based on max17042_battery.c
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mod_devicetable.h>
#include <linux/power_supply.h>
#include <linux/power/max17050_battery.h>
#include <linux/of.h>
/* Status register bits */
#define STATUS_POR_BIT (1 << 1)
#define STATUS_BI_BIT (1 << 11)
#define STATUS_BR_BIT (1 << 15)
/* Interrupt config/status bits */
#define CFG_ALRT_BIT_ENBL (1 << 2)
#define CFG_EXT_TEMP_BIT (1 << 8)
#define STATUS_INTR_SOCMIN_BIT (1 << 10)
#define STATUS_INTR_SOCMAX_BIT (1 << 14)
/* External battery power supply poll times */
#define EXT_BATT_FAST_PERIOD 100
#define EXT_BATT_SLOW_PERIOD 10000
/* Modelgauge M3 save/restore values */
struct max17050_learned_params {
u16 rcomp0;
u16 tempco;
u16 fullcap;
u16 fullcapnom;
u16 iavg_empty;
u16 qrtable00;
u16 qrtable10;
u16 qrtable20;
u16 qrtable30;
u16 cycles;
u16 param_version;
};
struct max17050_chip {
struct i2c_client *client;
struct power_supply battery;
struct power_supply *ext_battery;
bool power_supply_registered;
struct max17050_platform_data *pdata;
struct work_struct work;
struct delayed_work ext_batt_work;
struct mutex mutex;
struct timespec next_update_time;
bool suspended;
bool use_ext_temp;
int ext_temp;
bool init_done;
bool power_on_reset;
/* values read from chip */
u16 status;
u16 vcell;
u16 repcap;
u16 repsoc;
u16 temp;
u16 current_now;
u16 tte;
struct max17050_learned_params learned;
};
static int max17050_write_reg(struct i2c_client *client, u8 reg, u16 value)
{
int ret = i2c_smbus_write_word_data(client, reg, value);
if (ret < 0)
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
dev_dbg(&client->dev, "max17050 write: [%x]=%x", reg, value);
return ret;
}
static int max17050_read_reg(struct i2c_client *client, u8 reg)
{
int ret = i2c_smbus_read_word_data(client, reg);
if (ret < 0)
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
dev_dbg(&client->dev, "max17050 read: [%x]=%x", reg, ret);
return ret;
}
static int max17050_write_verify_reg(struct i2c_client *client, u8 reg,
u16 value)
{
int ret;
int read;
ret = i2c_smbus_write_word_data(client, reg, value);
if (ret < 0) {
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
return ret;
}
read = i2c_smbus_read_word_data(client, reg);
if (read < 0) {
dev_err(&client->dev, "%s: err %d\n", __func__, ret);
return ret;
}
if (read != value) {
dev_err(&client->dev, "%s: expected 0x%x, got 0x%x\n",
__func__, value, read);
return -EIO;
}
dev_dbg(&client->dev, "max17050 writev: [%x]=%x", reg, value);
return ret;
}
static int max17050_write_verify_block(struct i2c_client *client, u8 reg,
u16 *values, u8 len)
{
int ret;
int read;
u8 i;
for (i = 0; i < len; i++) {
ret = i2c_smbus_write_word_data(client, reg + i, values[i]);
if (ret < 0) {
dev_err(&client->dev, "%s: write err %d\n", __func__,
ret);
return ret;
}
read = i2c_smbus_read_word_data(client, reg + i);
if (read < 0) {
dev_err(&client->dev, "%s: read err %d\n", __func__,
read);
return read;
}
if (read != values[i]) {
dev_err(&client->dev,
"%s: addr 0x%x expected 0x%x, got 0x%x\n",
__func__, reg + i, values[i], read);
return -EIO;
}
}
return ret;
}
static void max17050_init_chip(struct max17050_chip *chip)
{
struct i2c_client *client = chip->client;
u16 vfsoc;
u16 remcap;
u16 repcap;
u8 i;
/* Wait 500ms after power up */
msleep(500);
/* Init config registers */
max17050_write_reg(client, MAX17050_RELAXCFG, chip->pdata->relaxcfg);
max17050_write_reg(client, MAX17050_CONFIG, chip->pdata->config);
max17050_write_reg(client, MAX17050_FILTERCFG, chip->pdata->filtercfg);
max17050_write_reg(client, MAX17050_LEARNCFG, chip->pdata->learncfg);
max17050_write_reg(client, MAX17050_MISCCFG, chip->pdata->misccfg);
max17050_write_reg(client, MAX17050_FULLSOCTHR, chip->pdata->fullsocthr);
/* Unlock model using magic lock numbers from Maxim */
max17050_write_reg(client, MAX17050_MODEL_LOCK1, 0x59);
max17050_write_reg(client, MAX17050_MODEL_LOCK2, 0xc4);
/* Write characterisation data */
max17050_write_verify_block(client, MAX17050_MODEL_TABLE,
chip->pdata->model, MODEL_SIZE);
/* Lock the model */
max17050_write_reg(client, MAX17050_MODEL_LOCK1, 0);
max17050_write_reg(client, MAX17050_MODEL_LOCK2, 0);
/* Verify that we can't read the model any more */
for (i = 0; i < MODEL_SIZE; i++)
if (max17050_read_reg(client, MAX17050_MODEL_TABLE + i))
dev_err(&client->dev, "model is non-zero");
/* Write custom parameters */
max17050_write_verify_reg(client, MAX17050_RCOMP0,
chip->pdata->rcomp0);
max17050_write_verify_reg(client, MAX17050_TEMPCO,
chip->pdata->tempco);
max17050_write_verify_reg(client, MAX17050_TEMPNOM,
chip->pdata->tempnom);
max17050_write_verify_reg(client, MAX17050_TGAIN,
chip->pdata->tgain);
max17050_write_verify_reg(client, MAX17050_TOFF,
chip->pdata->toff);
max17050_write_verify_reg(client, MAX17050_ICHGTERM,
chip->pdata->ichgterm);
max17050_write_verify_reg(client, MAX17050_V_EMPTY,
chip->pdata->vempty);
max17050_write_verify_reg(client, MAX17050_QRTABLE00,
chip->pdata->qrtable00);
max17050_write_verify_reg(client, MAX17050_QRTABLE10,
chip->pdata->qrtable10);
max17050_write_verify_reg(client, MAX17050_QRTABLE20,
chip->pdata->qrtable20);
max17050_write_verify_reg(client, MAX17050_QRTABLE30,
chip->pdata->qrtable30);
/* Update full capacity registers */
max17050_write_verify_reg(client, MAX17050_FULLCAP,
chip->pdata->capacity);
max17050_write_verify_reg(client, MAX17050_DESIGNCAP,
chip->pdata->vf_fullcap);
max17050_write_verify_reg(client, MAX17050_FULLCAPNOM,
chip->pdata->vf_fullcap);
/* Wait for VFSOC to be calculated */
msleep(350);
/* Write VFSOC value to VFSOC0, write QH to QH0 */
vfsoc = max17050_read_reg(client, MAX17050_VFSOC);
max17050_write_reg(client, MAX17050_VFSOC0_LOCK, 0x0080);
max17050_write_verify_reg(client, MAX17050_VFSOC0, vfsoc);
max17050_write_reg(client, MAX17050_VFSOC0_LOCK, 0);
/* Write temperature */
max17050_write_verify_reg(client, MAX17050_TEMP,
chip->pdata->temperature);
/* Load new capacity params */
remcap = (vfsoc * chip->pdata->vf_fullcap) / 25600;
max17050_write_verify_reg(client, MAX17050_REMCAP, remcap);
repcap = remcap;
max17050_write_verify_reg(client, MAX17050_REPCAP, repcap);
max17050_write_verify_reg(client, MAX17050_DQACC,
chip->pdata->vf_fullcap / 16);
max17050_write_verify_reg(client, MAX17050_DPACC, chip->pdata->dpacc);
max17050_write_verify_reg(client, MAX17050_FULLCAP,
chip->pdata->capacity);
max17050_write_reg(client, MAX17050_DESIGNCAP,
chip->pdata->vf_fullcap);
max17050_write_verify_reg(client, MAX17050_FULLCAPNOM,
chip->pdata->vf_fullcap);
/* Complete initialisation */
chip->status = max17050_read_reg(client, MAX17050_STATUS);
max17050_write_verify_reg(client, MAX17050_STATUS,
chip->status & ~(STATUS_POR_BIT | STATUS_BR_BIT |
STATUS_BI_BIT));
/* Write custom parameter version */
max17050_write_verify_reg(client, MAX17050_CUSTOMVER,
chip->pdata->param_version);
/* Set the parameter init status */
if (chip->status & (STATUS_POR_BIT | STATUS_BI_BIT))
chip->power_on_reset = true;
}
/* Must call with mutex locked */
static void max17050_save_learned_params(struct max17050_chip *chip)
{
struct i2c_client *client = chip->client;
chip->learned.rcomp0 = max17050_read_reg(client,
MAX17050_RCOMP0);
chip->learned.tempco = max17050_read_reg(client,
MAX17050_TEMPCO);
chip->learned.fullcap = max17050_read_reg(client,
MAX17050_FULLCAP);
chip->learned.cycles = max17050_read_reg(client,
MAX17050_CYCLES);
chip->learned.fullcapnom = max17050_read_reg(client,
MAX17050_FULLCAPNOM);
chip->learned.iavg_empty = max17050_read_reg(client,
MAX17050_IAVG_EMPTY);
chip->learned.qrtable00 = max17050_read_reg(client,
MAX17050_QRTABLE00);
chip->learned.qrtable10 = max17050_read_reg(client,
MAX17050_QRTABLE10);
chip->learned.qrtable20 = max17050_read_reg(client,
MAX17050_QRTABLE20);
chip->learned.qrtable30 = max17050_read_reg(client,
MAX17050_QRTABLE30);
chip->learned.param_version = max17050_read_reg(client,
MAX17050_CUSTOMVER);
}
/* Must call with mutex locked */
static void max17050_restore_learned_params(struct max17050_chip *chip)
{
struct i2c_client *client = chip->client;
u16 remcap;
/* Skip restore when custom param version has changed */
if (chip->learned.param_version !=
max17050_read_reg(client, MAX17050_CUSTOMVER))
return;
max17050_write_verify_reg(client, MAX17050_RCOMP0,
chip->learned.rcomp0);
max17050_write_verify_reg(client, MAX17050_TEMPCO,
chip->learned.tempco);
max17050_write_verify_reg(client, MAX17050_IAVG_EMPTY,
chip->learned.iavg_empty);
max17050_write_verify_reg(client, MAX17050_FULLCAPNOM,
chip->learned.fullcapnom);
max17050_write_verify_reg(client, MAX17050_QRTABLE00,
chip->learned.qrtable00);
max17050_write_verify_reg(client, MAX17050_QRTABLE10,
chip->learned.qrtable10);
max17050_write_verify_reg(client, MAX17050_QRTABLE20,
chip->learned.qrtable20);
max17050_write_verify_reg(client, MAX17050_QRTABLE30,
chip->learned.qrtable30);
/* Wait for VFSOC to be calculated */
msleep(350);
remcap = (max17050_read_reg(client, MAX17050_SOC) *
max17050_read_reg(client, MAX17050_FULLCAP0)) / 25600;
max17050_write_verify_reg(client, MAX17050_REMCAP, remcap);
max17050_write_verify_reg(client, MAX17050_FULLCAP,
chip->learned.fullcap);
max17050_write_verify_reg(client, MAX17050_DQACC,
chip->learned.fullcap / 16);
max17050_write_verify_reg(client, MAX17050_DPACC, chip->pdata->dpacc);
msleep(350);
max17050_write_verify_reg(client, MAX17050_CYCLES,
chip->learned.cycles);
if (chip->learned.cycles > 0xff) {
/* advance to learnstage 7 */
max17050_write_verify_reg(client, MAX17050_LEARNCFG,
0x0676);
}
}
static ssize_t max17050_learned_read(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 max17050_chip *chip = dev_get_drvdata(dev);
if (count == 0)
return 0;
else if (count < sizeof(struct max17050_learned_params))
return -EINVAL;
mutex_lock(&chip->mutex);
max17050_save_learned_params(chip);
memcpy(buf, &chip->learned, sizeof(struct max17050_learned_params));
mutex_unlock(&chip->mutex);
return count;
}
static ssize_t max17050_learned_write(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 max17050_chip *chip = dev_get_drvdata(dev);
if (count == 0)
return 0;
else if (count < sizeof(struct max17050_learned_params))
return -EINVAL;
mutex_lock(&chip->mutex);
memcpy(&chip->learned, buf, sizeof(struct max17050_learned_params));
max17050_restore_learned_params(chip);
mutex_unlock(&chip->mutex);
return count;
}
static struct bin_attribute max17050_learned_attr = {
.attr = {
.name = "learned",
.mode = S_IRUGO | S_IWUSR,
},
.size = sizeof(struct max17050_learned_params),
.read = max17050_learned_read,
.write = max17050_learned_write,
};
static ssize_t max17050_show_init_done(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct max17050_chip *chip = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", chip->init_done);
}
static DEVICE_ATTR(init_done, S_IRUGO,
max17050_show_init_done, NULL);
static ssize_t max17050_show_power_on_reset(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct max17050_chip *chip = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", chip->power_on_reset);
}
static DEVICE_ATTR(power_on_reset, S_IRUGO,
max17050_show_power_on_reset, NULL);
static void max17050_update_ext_temp(struct work_struct *work)
{
struct max17050_chip *chip =
container_of(work, struct max17050_chip, ext_batt_work.work);
union power_supply_propval propval = {0,};
u16 u16_value;
if (!chip->ext_battery)
chip->ext_battery = power_supply_get_by_name("battery");
if (!chip->ext_battery) {
/* Power supply not ready - try again soon */
schedule_delayed_work(&chip->ext_batt_work,
msecs_to_jiffies(EXT_BATT_FAST_PERIOD));
return;
}
/* Get the temperature from the external power supply */
chip->ext_battery->get_property(chip->ext_battery,
POWER_SUPPLY_PROP_TEMP, &propval);
if (chip->ext_temp != propval.intval) {
chip->ext_temp = propval.intval;
/* Write the temperature to the MAX17050 */
u16_value = (u16)(chip->ext_temp * 256 / 10);
mutex_lock(&chip->mutex);
max17050_write_verify_reg(chip->client, MAX17050_TEMP,
u16_value);
mutex_unlock(&chip->mutex);
}
/* Update again after some time */
schedule_delayed_work(&chip->ext_batt_work,
msecs_to_jiffies(EXT_BATT_SLOW_PERIOD));
}
/* Must call with mutex locked */
static void max17050_update(struct max17050_chip *chip)
{
struct i2c_client *client = chip->client;
/* Check for power-on-reset or battery insertion */
chip->status = max17050_read_reg(client, MAX17050_STATUS);
if (chip->status == (u16)-EIO) {
return;
}
if (chip->status & (STATUS_POR_BIT | STATUS_BI_BIT))
max17050_init_chip(chip);
chip->repcap = max17050_read_reg(client, MAX17050_REPCAP);
chip->repsoc = max17050_read_reg(client, MAX17050_REPSOC);
chip->tte = max17050_read_reg(client, MAX17050_TTE);
chip->current_now = max17050_read_reg(client, MAX17050_CURRENT);
if (!chip->use_ext_temp || !chip->ext_battery)
chip->temp = max17050_read_reg(client, MAX17050_TEMP);
chip->vcell = max17050_read_reg(client, MAX17050_VCELL);
chip->learned.cycles = max17050_read_reg(client, MAX17050_CYCLES);
/* next update must be at least 1 second later */
ktime_get_ts(&chip->next_update_time);
monotonic_to_bootbased(&chip->next_update_time);
chip->next_update_time.tv_sec++;
}
static int max17050_scale_clamp_soc(struct max17050_chip *chip)
{
int adj_soc;
if (chip->pdata->full_soc <= chip->pdata->empty_soc) {
pr_err("%s: Invalid soc range for scaling\n", __func__);
return chip->repsoc >> 8;
}
/*
* Scale repsoc to the range between full_soc and empty_soc. Use an
* additional 3 bits of repsoc (0.125% units) for more accuracy.
*/
adj_soc = chip->repsoc >> 5;
adj_soc = (adj_soc - chip->pdata->empty_soc * 8) * 100 /
((chip->pdata->full_soc - chip->pdata->empty_soc) * 8);
if (adj_soc > 100)
adj_soc = 100;
else if (adj_soc < 0)
adj_soc = 0;
return adj_soc;
}
static enum power_supply_property max17050_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_CURRENT_NOW,
};
static int max17050_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
{
struct max17050_chip *chip = container_of(psy,
struct max17050_chip, battery);
struct timespec now;
s16 s16_value;
if (chip->suspended)
return -EAGAIN;
ktime_get_ts(&now);
monotonic_to_bootbased(&now);
if (timespec_compare(&now, &chip->next_update_time) >= 0) {
mutex_lock(&chip->mutex);
max17050_update(chip);
mutex_unlock(&chip->mutex);
}
switch (psp) {
case POWER_SUPPLY_PROP_PRESENT:
if (chip->status & MAX17050_STATUS_BATTABSENT)
val->intval = 0;
else
val->intval = 1;
break;
case POWER_SUPPLY_PROP_CYCLE_COUNT:
val->intval = chip->learned.cycles / 100;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
val->intval = chip->vcell * 625 / 8;
break;
case POWER_SUPPLY_PROP_CAPACITY:
val->intval = max17050_scale_clamp_soc(chip);
break;
case POWER_SUPPLY_PROP_TEMP:
if (chip->use_ext_temp && chip->ext_battery) {
val->intval = chip->ext_temp;
} else {
/* cast to s16 */
s16_value = (s16)chip->temp;
/* sign extend to s32 */
val->intval = (s32)s16_value;
/* units are 1/256, and temp is reported in C * 10 */
val->intval = (val->intval * 10) / 256;
}
break;
case POWER_SUPPLY_PROP_CURRENT_NOW:
/* cast to s16 */
s16_value = (s16)chip->current_now;
/* sign extend to s32 */
val->intval = (s32)s16_value;
val->intval *= 1562500 / chip->pdata->r_sns;
/* negate (charging is negative by convention) */
val->intval *= -1;
break;
default:
return -EINVAL;
}
return 0;
}
static void max17050_set_soc_thresholds(struct max17050_chip *chip,
s16 threshold)
{
s16 soc_now;
s16 soc_max;
s16 soc_min;
soc_now = max17050_read_reg(chip->client, MAX17050_REPSOC) >> 8;
soc_max = soc_now + threshold;
if (soc_max > 100)
soc_max = 100;
soc_min = soc_now - threshold;
if (soc_min < 0)
soc_min = 0;
max17050_write_reg(chip->client, MAX17050_SALRT_TH,
(u16)soc_min | ((u16)soc_max << 8));
}
static irqreturn_t max17050_interrupt(int id, void *dev)
{
struct max17050_chip *chip = dev;
struct i2c_client *client = chip->client;
u16 val;
pr_debug("%s: interrupt occured, ID = %d\n", __func__, id);
val = max17050_read_reg(client, MAX17050_STATUS);
/* Signal userspace when the capacity exceeds the limits */
if ((val & STATUS_INTR_SOCMIN_BIT) || (val & STATUS_INTR_SOCMAX_BIT)) {
/* Clear interrupt status bits */
max17050_write_reg(client, MAX17050_STATUS, val &
~(STATUS_INTR_SOCMIN_BIT | STATUS_INTR_SOCMAX_BIT));
/* Reset capacity thresholds */
max17050_set_soc_thresholds(chip, 5);
power_supply_changed(&chip->battery);
}
return IRQ_HANDLED;
}
static void max17050_complete_init(struct max17050_chip *chip)
{
struct i2c_client *client = chip->client;
int val;
if (sysfs_create_bin_file(&client->dev.kobj, &max17050_learned_attr))
dev_err(&client->dev, "sysfs_create_bin_file failed");
if (device_create_file(&client->dev, &dev_attr_init_done))
dev_err(&client->dev, "device_create_file failed");
if (device_create_file(&client->dev, &dev_attr_power_on_reset))
dev_err(&client->dev, "device_create_file failed");
if (power_supply_register(&client->dev, &chip->battery))
dev_err(&client->dev, "failed: power supply register");
else
chip->power_supply_registered = true;
if (client->irq) {
/* Set capacity thresholds to +/- 5% of current capacity */
max17050_set_soc_thresholds(chip, 5);
/* Enable capacity interrupts */
val = max17050_read_reg(client, MAX17050_CONFIG);
max17050_write_reg(client, MAX17050_CONFIG,
val | CFG_ALRT_BIT_ENBL);
}
if (chip->use_ext_temp && chip->pdata->ext_batt_psy)
schedule_delayed_work(&chip->ext_batt_work, 0);
chip->init_done = true;
}
static void max17050_init_worker(struct work_struct *work)
{
struct max17050_chip *chip = container_of(work,
struct max17050_chip, work);
max17050_init_chip(chip);
max17050_complete_init(chip);
}
static struct max17050_platform_data *
max17050_get_pdata(struct device *dev)
{
struct device_node *np = dev->of_node;
u32 prop;
struct max17050_platform_data *pdata;
const u8 *model;
int len;
if (!np)
return dev->platform_data;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return NULL;
/*
* Require current sense resistor value to be specified for
* current-sense functionality to be enabled at all.
*/
if (of_property_read_u32(np, "maxim,rsns-microohm", &prop) == 0) {
pdata->r_sns = prop;
pdata->enable_current_sense = true;
} else {
pdata->r_sns = MAX17050_DEFAULT_SNS_RESISTOR;
}
pdata->ext_batt_psy = of_property_read_bool(np, "maxim,ext_batt_psy");
if (of_property_read_u32(np, "maxim,relaxcfg", &prop) == 0)
pdata->relaxcfg = prop;
if (of_property_read_u32(np, "maxim,config", &prop) == 0)
pdata->config = prop;
if (of_property_read_u32(np, "maxim,filtercfg", &prop) == 0)
pdata->filtercfg = prop;
if (of_property_read_u32(np, "maxim,learncfg", &prop) == 0)
pdata->learncfg = prop;
if (of_property_read_u32(np, "maxim,misccfg", &prop) == 0)
pdata->misccfg = prop;
if (of_property_read_u32(np, "maxim,fullsocthr", &prop) == 0)
pdata->fullsocthr = prop;
if (of_property_read_u32(np, "maxim,rcomp0", &prop) == 0)
pdata->rcomp0 = prop;
if (of_property_read_u32(np, "maxim,tempco", &prop) == 0)
pdata->tempco = prop;
if (of_property_read_u32(np, "maxim,tempnom", &prop) == 0)
pdata->tempnom = prop;
if (of_property_read_u32(np, "maxim,tgain", &prop) == 0)
pdata->tgain = prop;
if (of_property_read_u32(np, "maxim,toff", &prop) == 0)
pdata->toff = prop;
if (of_property_read_u32(np, "maxim,ichgterm", &prop) == 0)
pdata->ichgterm = prop;
if (of_property_read_u32(np, "maxim,vempty", &prop) == 0)
pdata->vempty = prop;
if (of_property_read_u32(np, "maxim,qrtable00", &prop) == 0)
pdata->qrtable00 = prop;
if (of_property_read_u32(np, "maxim,qrtable10", &prop) == 0)
pdata->qrtable10 = prop;
if (of_property_read_u32(np, "maxim,qrtable20", &prop) == 0)
pdata->qrtable20 = prop;
if (of_property_read_u32(np, "maxim,qrtable30", &prop) == 0)
pdata->qrtable30 = prop;
if (of_property_read_u32(np, "maxim,capacity", &prop) == 0)
pdata->capacity = prop;
if (of_property_read_u32(np, "maxim,vf_fullcap", &prop) == 0)
pdata->vf_fullcap = prop;
if (of_property_read_u32(np, "maxim,temperature", &prop) == 0)
pdata->temperature = prop;
if (of_property_read_u32(np, "maxim,dpacc", &prop) == 0)
pdata->dpacc = prop;
if (of_property_read_u32(np, "maxim,empty-soc", &prop) == 0)
pdata->empty_soc = prop;
else
pdata->empty_soc = 0;
if (of_property_read_u32(np, "maxim,full-soc", &prop) == 0)
pdata->full_soc = prop;
else
pdata->full_soc = 100;
if (of_property_read_u32(np, "maxim,param-version", &prop) == 0)
pdata->param_version = prop;
model = of_get_property(np, "maxim,model", &len);
if (model && ((len / 2) == MODEL_SIZE)) {
int i;
for (i = 0; i < MODEL_SIZE; i++) {
pdata->model[i] = *model++ << 8;
pdata->model[i] |= *model++;
}
}
return pdata;
}
static int max17050_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct max17050_chip *chip;
int ret = 0;
bool new_custom_param = false;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -EIO;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->client = client;
chip->pdata = max17050_get_pdata(&client->dev);
if (!chip->pdata) {
dev_err(&client->dev, "no platform data provided\n");
devm_kfree(&client->dev, chip);
return -EINVAL;
}
i2c_set_clientdata(client, chip);
/*
* If ext_batt_psy is true, then an external device publishes
* a POWER_SUPPLY_TYPE_BATTERY, so this driver will publish its
* data via the POWER_SUPPLY_TYPE_BMS type.
*/
if (chip->pdata->ext_batt_psy) {
chip->battery.name = "bms";
chip->battery.type = POWER_SUPPLY_TYPE_BMS;
} else {
chip->battery.name = "battery";
chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
}
chip->battery.get_property = max17050_get_property;
chip->battery.properties = max17050_battery_props;
chip->battery.num_properties = ARRAY_SIZE(max17050_battery_props);
/*
* When current is not measured, CURRENT_NOW property should be
* invisible.
*/
if (!chip->pdata->enable_current_sense)
chip->battery.num_properties -= 1;
chip->use_ext_temp = !!(chip->pdata->config & CFG_EXT_TEMP_BIT);
if (chip->use_ext_temp && chip->pdata->ext_batt_psy)
INIT_DELAYED_WORK(&chip->ext_batt_work,
max17050_update_ext_temp);
if (client->irq) {
ret = request_threaded_irq(client->irq, NULL,
max17050_interrupt,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
chip->battery.name, chip);
if (ret) {
dev_err(&client->dev, "cannot enable irq");
return ret;
} else {
enable_irq_wake(client->irq);
}
}
INIT_WORK(&chip->work, max17050_init_worker);
mutex_init(&chip->mutex);
/*
* If the version of custom parameters is changed, the init chip
* should be called even if POR doesn't happen.
* For checking parameter change, the reserved register, 0x20,
* is defined as custom version register.
*/
if (max17050_read_reg(client, MAX17050_CUSTOMVER) !=
chip->pdata->param_version)
new_custom_param = true;
if ((max17050_read_reg(client, MAX17050_STATUS) &
(STATUS_POR_BIT | STATUS_BI_BIT)) ||
new_custom_param)
schedule_work(&chip->work);
else
max17050_complete_init(chip);
return ret;
}
static int max17050_remove(struct i2c_client *client)
{
struct max17050_chip *chip = i2c_get_clientdata(client);
device_remove_file(&client->dev, &dev_attr_power_on_reset);
device_remove_file(&client->dev, &dev_attr_init_done);
sysfs_remove_bin_file(&client->dev.kobj, &max17050_learned_attr);
if (client->irq)
disable_irq_wake(client->irq);
if (chip->power_supply_registered)
power_supply_unregister(&chip->battery);
i2c_set_clientdata(client, NULL);
devm_kfree(&client->dev, chip);
return 0;
}
static int max17050_pm_prepare(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct max17050_chip *chip = i2c_get_clientdata(client);
/* Cancel any pending work, if necessary */
if (chip->use_ext_temp && chip->pdata->ext_batt_psy)
cancel_delayed_work_sync(&chip->ext_batt_work);
chip->suspended = true;
if (chip->client->irq) {
disable_irq(chip->client->irq);
enable_irq_wake(chip->client->irq);
}
return 0;
}
static void max17050_pm_complete(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct max17050_chip *chip = i2c_get_clientdata(client);
chip->suspended = false;
if (chip->client->irq) {
disable_irq_wake(chip->client->irq);
enable_irq(chip->client->irq);
}
/* Schedule a temperature update, if needed */
if (chip->use_ext_temp && chip->pdata->ext_batt_psy)
schedule_delayed_work(&chip->ext_batt_work, 0);
}
static const struct dev_pm_ops max17050_pm_ops = {
.prepare = max17050_pm_prepare,
.complete = max17050_pm_complete,
};
static const struct of_device_id max17050_dt_match[] = {
{ .compatible = "maxim,max17050" },
{ },
};
MODULE_DEVICE_TABLE(of, max17050_dt_match);
static const struct i2c_device_id max17050_id[] = {
{ "max17050", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max17050_id);
static struct i2c_driver max17050_i2c_driver = {
.driver = {
.name = "max17050",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(max17050_dt_match),
.pm = &max17050_pm_ops,
},
.probe = max17050_probe,
.remove = max17050_remove,
.id_table = max17050_id,
};
module_i2c_driver(max17050_i2c_driver);
MODULE_AUTHOR("Simon Wilson <simonwilson@google.com>");
MODULE_DESCRIPTION("MAX17050 Fuel Gauge");
MODULE_LICENSE("GPL");