summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/board-kai.c19
-rw-r--r--drivers/power/max17048_battery.c374
-rw-r--r--include/linux/max17048_battery.h16
3 files changed, 303 insertions, 106 deletions
diff --git a/arch/arm/mach-tegra/board-kai.c b/arch/arm/mach-tegra/board-kai.c
index 0a9cbd117d9b..45acedc363b0 100644
--- a/arch/arm/mach-tegra/board-kai.c
+++ b/arch/arm/mach-tegra/board-kai.c
@@ -248,16 +248,25 @@ static struct tegra_i2c_platform_data kai_i2c5_platform_data = {
.arb_recovery = arb_lost_recovery,
};
-struct max17048_platform_data max17048_pdata = {
- .charger_online = smb349_charger_type,
- .battery_online = smb349_battery_online,
- .charging_status = smb349_charging_status,
+struct max17048_battery_model max17048_mdata = {
+ .rcomp = 170,
+ .soccheck_A = 252,
+ .soccheck_B = 254,
+ .bits = 19,
+ .alert_threshold = 0x00,
+ .one_percent_alerts = 0x40,
+ .alert_on_reset = 0x40,
+ .rcomp_seg = 0x0800,
+ .hibernate = 0x3080,
+ .vreset = 0x9696,
+ .valert = 0xD4AA,
+ .ocvtest = 55600,
};
static struct i2c_board_info kai_i2c4_max17048_board_info[] = {
{
I2C_BOARD_INFO("max17048", 0x36),
- .platform_data = &max17048_pdata,
+ .platform_data = &max17048_mdata,
},
};
diff --git a/drivers/power/max17048_battery.c b/drivers/power/max17048_battery.c
index cf8ea0bfdd65..3f5fa04fa52e 100644
--- a/drivers/power/max17048_battery.c
+++ b/drivers/power/max17048_battery.c
@@ -23,20 +23,22 @@
#include <linux/slab.h>
#include <linux/max17048_battery.h>
-#define MAX17048_VCELL_MSB 0x02
-#define MAX17048_VCELL_LSB 0x03
-#define MAX17048_SOC_MSB 0x04
-#define MAX17048_SOC_LSB 0x05
-#define MAX17048_MODE_MSB 0x06
-#define MAX17048_MODE_LSB 0x07
-#define MAX17048_VER_MSB 0x08
-#define MAX17048_VER_LSB 0x09
-#define MAX17048_RCOMP_MSB 0x0C
-#define MAX17048_RCOMP_LSB 0x0D
-#define MAX17048_CMD_MSB 0xFE
-#define MAX17048_CMD_LSB 0xFF
-#define RESET_MSB 0x54
-#define RESET_LSB 0x00
+#define MAX17048_VCELL 0x02
+#define MAX17048_SOC 0x04
+#define MAX17048_VER 0x08
+#define MAX17048_HIBRT 0x0A
+#define MAX17048_CONFIG 0x0C
+#define MAX17048_OCV 0x0E
+#define MAX17048_VLRT 0x14
+#define MAX17048_VRESET 0x18
+#define MAX17048_STATUS 0x1A
+#define MAX17048_UNLOCK 0x3E
+#define MAX17048_TABLE 0x40
+#define MAX17048_RCOMPSEG1 0x80
+#define MAX17048_RCOMPSEG2 0x90
+#define MAX17048_CMD 0xFF
+#define MAX17048_UNLOCK_VALUE 0x4a57
+#define MAX17048_RESET_VALUE 0x5400
#define MAX17048_DELAY 1000
#define MAX17048_BATTERY_FULL 95
#define MAX17048_VERSION_NO 0x11
@@ -47,7 +49,7 @@ struct max17048_chip {
struct power_supply battery;
struct power_supply ac;
struct power_supply usb;
- struct max17048_platform_data *pdata;
+ struct max17048_battery_model *model_data;
/* State Of Connect */
int ac_online;
@@ -62,10 +64,43 @@ struct max17048_chip {
int lasttime_vcell;
int lasttime_soc;
int lasttime_status;
- int lasttime_ac_online;
- int lasttime_usb_online;
};
+uint8_t max17048_custom_data[] = {
+ 0xAA, 0x00, 0xB1, 0xF0, 0xB7, 0xE0, 0xB9, 0x60, 0xBB, 0x80,
+ 0xBC, 0x40, 0xBD, 0x30, 0xBD, 0x50, 0xBD, 0xF0, 0xBE, 0x40,
+ 0xBF, 0xD0, 0xC0, 0x90, 0xC4, 0x30, 0xC7, 0xC0, 0xCA, 0x60,
+ 0xCF, 0x30, 0x01, 0x20, 0x09, 0xC0, 0x1F, 0xC0, 0x2B, 0xE0,
+ 0x4F, 0xC0, 0x30, 0x00, 0x47, 0x80, 0x4F, 0xE0, 0x77, 0x00,
+ 0x15, 0x60, 0x46, 0x20, 0x13, 0x80, 0x1A, 0x60, 0x12, 0x20,
+ 0x14, 0xA0, 0x14, 0xA0};
+
+static int max17048_write_word(struct i2c_client *client, int reg, u16 value)
+{
+ int ret;
+
+ ret = i2c_smbus_write_word_data(client, reg, swab16(value));
+
+ if (ret < 0)
+ dev_err(&client->dev, "%s(): Failed in writing register"
+ "0x%02x err %d\n", __func__, reg, ret);
+
+ return ret;
+}
+
+static uint16_t max17048_read_word(struct i2c_client *client, int reg)
+{
+ uint16_t ret;
+
+ ret = i2c_smbus_read_word_data(client, reg);
+
+ if (ret < 0)
+ dev_err(&client->dev, "%s(): Failed in reading register"
+ "0x%02x err %d\n", __func__, reg, ret);
+
+ return swab16(ret);
+}
+
static int max17048_get_property(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -119,94 +154,33 @@ static int max17048_usb_get_property(struct power_supply *psy,
return 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;
-}
-
-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 void max17048_reset(struct i2c_client *client)
-{
- max17048_write_reg(client, MAX17048_CMD_MSB, RESET_MSB);
- max17048_write_reg(client, MAX17048_CMD_LSB, RESET_LSB);
-}
-
static void max17048_get_vcell(struct i2c_client *client)
{
struct max17048_chip *chip = i2c_get_clientdata(client);
- u8 msb;
- u8 lsb;
+ uint16_t vcell;
- msb = max17048_read_reg(client, MAX17048_VCELL_MSB);
- lsb = max17048_read_reg(client, MAX17048_VCELL_LSB);
+ vcell = max17048_read_word(client, MAX17048_VCELL);
+ if (vcell < 0)
+ dev_err(&client->dev, "%s: err %d\n", __func__, vcell);
- chip->vcell = (msb << 4) + (lsb >> 4);
+ chip->vcell = vcell;
}
static void max17048_get_soc(struct i2c_client *client)
{
struct max17048_chip *chip = i2c_get_clientdata(client);
- u8 msb;
- u8 lsb;
+ uint16_t soc;
- msb = max17048_read_reg(client, MAX17048_SOC_MSB);
+ soc = max17048_read_word(client, MAX17048_SOC);
+ if (soc < 0)
+ dev_err(&client->dev, "%s: err %d\n", __func__, soc);
- chip->soc = msb;
+ chip->soc = soc >> 9;
}
static uint16_t max17048_get_version(struct i2c_client *client)
{
- return swab16(i2c_smbus_read_word_data(client, MAX17048_VER_MSB));
-}
-
-static void max17048_get_online(struct i2c_client *client)
-{
- struct max17048_chip *chip = i2c_get_clientdata(client);
-
- if (chip->pdata->charging_status && chip->pdata->charging_status()) {
- if (chip->pdata->charger_online &&
- chip->pdata->charger_online()) {
- chip->ac_online = 1;
- chip->usb_online = 0;
- } else {
- chip->ac_online = 0;
- chip->usb_online = 1;
- }
- } else {
- chip->ac_online = 0;
- chip->usb_online = 0;
- }
-}
-
-static void max17048_get_status(struct i2c_client *client)
-{
- struct max17048_chip *chip = i2c_get_clientdata(client);
-
- if (chip->pdata->charging_status())
- chip->status = POWER_SUPPLY_STATUS_CHARGING;
- else
- chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
-
- if (chip->soc > MAX17048_BATTERY_FULL)
- chip->status = POWER_SUPPLY_STATUS_FULL;
+ return swab16(i2c_smbus_read_word_data(client, MAX17048_VER));
}
static void max17048_work(struct work_struct *work)
@@ -217,28 +191,45 @@ static void max17048_work(struct work_struct *work)
max17048_get_vcell(chip->client);
max17048_get_soc(chip->client);
- max17048_get_online(chip->client);
- max17048_get_status(chip->client);
if (chip->vcell != chip->lasttime_vcell ||
chip->soc != chip->lasttime_soc ||
- chip->ac_online != chip->lasttime_ac_online ||
- chip->usb_online != chip->lasttime_usb_online ||
chip->status != chip->lasttime_status) {
chip->lasttime_vcell = chip->vcell;
chip->lasttime_soc = chip->soc;
- chip->lasttime_status = chip->status;
- chip->lasttime_ac_online = chip->ac_online;
- chip->lasttime_usb_online = chip->usb_online;
power_supply_changed(&chip->battery);
- power_supply_changed(&chip->usb);
- power_supply_changed(&chip->ac);
}
schedule_delayed_work(&chip->work, MAX17048_DELAY);
}
+static void max17048_battery_status(enum charging_states status,
+ enum charger_type chrg_type, void *data)
+{
+ struct max17048_chip *chip = data;
+
+ chip->ac_online = 0;
+ chip->usb_online = 0;
+
+ if (chrg_type == AC)
+ chip->ac_online = 1;
+ else if (chrg_type == USB)
+ chip->usb_online = 1;
+
+ if (status == progress)
+ chip->status = POWER_SUPPLY_STATUS_CHARGING;
+ else
+ chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
+
+ if (chip->soc > MAX17048_BATTERY_FULL)
+ chip->status = POWER_SUPPLY_STATUS_FULL;
+
+ power_supply_changed(&chip->battery);
+ power_supply_changed(&chip->usb);
+ power_supply_changed(&chip->ac);
+}
+
static enum power_supply_property max17048_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
@@ -253,10 +244,182 @@ static enum power_supply_property max17048_usb_props[] = {
POWER_SUPPLY_PROP_ONLINE,
};
+static int max17048_write_rcomp_seg(struct i2c_client *client,
+ uint16_t rcomp_seg)
+{
+ uint8_t rs1, rs2;
+ int ret;
+
+ rs2 = rcomp_seg | 0x00FF;
+ rs1 = rcomp_seg >> 8;
+ uint8_t rcomp_seg_table[16] = { rs1, rs2, rs1, rs2,
+ rs1, rs2, rs1, rs2,
+ rs1, rs2, rs1, rs2,
+ rs1, rs2, rs1, rs2};
+
+ ret = i2c_smbus_write_i2c_block_data(client, MAX17048_RCOMPSEG1,
+ 16, (uint8_t *)rcomp_seg_table);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = i2c_smbus_write_i2c_block_data(client, MAX17048_RCOMPSEG2,
+ 16, (uint8_t *)rcomp_seg_table);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max17048_load_model_data(struct max17048_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ struct max17048_battery_model *mdata = chip->model_data;
+ uint16_t soc_tst, ocv;
+ int i, ret = 0;
+
+ /* read OCV */
+ ocv = max17048_read_word(client, MAX17048_OCV);
+ if (ocv == 0xffff) {
+ dev_err(&client->dev, "%s: Failed in unlocking"
+ "max17048 err: %d\n", __func__, ocv);
+ return -1;
+ }
+
+ /* write custom model data */
+ for (i = 0; i < 4; i += 1) {
+ if (i2c_smbus_write_i2c_block_data(client,
+ (MAX17048_TABLE+i*16), 16,
+ &max17048_custom_data[i*0x10]) < 0) {
+ dev_err(&client->dev, "%s: error writing model data:\n",
+ __func__);
+ return -1;
+ }
+ }
+
+ /* Write OCV Test value */
+ ret = max17048_write_word(client, MAX17048_OCV, mdata->ocvtest);
+ if (ret < 0)
+ return ret;
+
+ ret = max17048_write_rcomp_seg(client, mdata->rcomp_seg);
+ if (ret < 0)
+ return ret;
+
+ /* Disable hibernate */
+ ret = max17048_write_word(client, MAX17048_HIBRT, 0x0000);
+ if (ret < 0)
+ return ret;
+
+ /* Lock model access */
+ ret = max17048_write_word(client, MAX17048_UNLOCK, 0x0000);
+ if (ret < 0)
+ return ret;
+
+ /* Delay between 150ms to 600ms */
+ mdelay(200);
+
+ /* Read SOC Register and compare to expected result */
+ soc_tst = max17048_read_word(client, MAX17048_SOC);
+ if (!((soc_tst >> 8) >= mdata->soccheck_A &&
+ (soc_tst >> 8) <= mdata->soccheck_B)) {
+ dev_err(&client->dev, "%s: soc comparison failed %d\n",
+ __func__, ret);
+ return ret;
+ } else {
+ dev_info(&client->dev, "MAX17048 Custom data"
+ " loading successfull\n");
+ }
+
+ /* unlock model access */
+ ret = max17048_write_word(client, MAX17048_UNLOCK,
+ MAX17048_UNLOCK_VALUE);
+ if (ret < 0)
+ return ret;
+
+ /* Restore OCV */
+ ret = max17048_write_word(client, MAX17048_OCV, ocv);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+static int max17048_initialize(struct max17048_chip *chip)
+{
+ uint8_t ret, config, status;
+ uint16_t wrt_status;
+ struct i2c_client *client = chip->client;
+ struct max17048_battery_model *mdata = chip->model_data;
+
+ /* unlock model access */
+ ret = max17048_write_word(client, MAX17048_UNLOCK,
+ MAX17048_UNLOCK_VALUE);
+ if (ret < 0)
+ return ret;
+
+ /* load model data */
+ ret = max17048_load_model_data(chip);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: err %d\n", __func__, ret);
+ return ret;
+ }
+
+ if (mdata->bits == 19)
+ config = 32 - (mdata->alert_threshold * 2);
+ else if (mdata->bits == 18)
+ config = 32 - mdata->alert_threshold;
+
+ config = mdata->one_percent_alerts | config;
+
+ ret = max17048_write_word(client, MAX17048_CONFIG,
+ ((mdata->rcomp << 8) | config));
+ if (ret < 0)
+ return ret;
+
+ /* Voltage Alert configuration */
+ ret = max17048_write_word(client, MAX17048_VLRT, mdata->valert);
+ if (ret < 0)
+ return ret;
+
+ /* Hibernate configuration */
+ ret = max17048_write_word(client, MAX17048_HIBRT, mdata->hibernate);
+ if (ret < 0)
+ return ret;
+
+ ret = max17048_write_word(client, MAX17048_VRESET, mdata->vreset);
+ if (ret < 0)
+ return ret;
+
+ /* clears the reset indicator */
+ ret = max17048_read_word(client, MAX17048_STATUS);
+ if (ret < 0)
+ return ret;
+
+ /* Sets the EnVR bit if selected */
+ status = (ret & 0xFE) | mdata->alert_on_reset;
+ wrt_status = status << 8;
+
+ ret = max17048_write_word(client, MAX17048_STATUS, wrt_status);
+ if (ret < 0)
+ return ret;
+
+ /* Lock model access */
+ ret = max17048_write_word(client, MAX17048_UNLOCK, 0x0000);
+ if (ret < 0)
+ return ret;
+
+ /* Add delay */
+ mdelay(200);
+ return 0;
+}
+
static int __devinit max17048_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct max17048_chip *chip;
int ret;
uint16_t version;
@@ -266,7 +429,7 @@ static int __devinit max17048_probe(struct i2c_client *client,
return -ENOMEM;
chip->client = client;
- chip->pdata = client->dev.platform_data;
+ chip->model_data = client->dev.platform_data;
chip->ac_online = 0;
chip->usb_online = 0;
@@ -279,6 +442,16 @@ static int __devinit max17048_probe(struct i2c_client *client,
}
dev_info(&client->dev, "MAX17048 Fuel-Gauge Ver 0x%x\n", version);
+ ret = max17048_initialize(chip);
+ if (ret < 0) {
+ dev_err(&client->dev, "Error: Initializing fuel-gauge\n");
+ goto error2;
+ }
+
+ ret = register_callback(max17048_battery_status, chip);
+ if (ret < 0)
+ goto error2;
+
chip->battery.name = "battery";
chip->battery.type = POWER_SUPPLY_TYPE_BATTERY;
chip->battery.get_property = max17048_get_property;
@@ -314,7 +487,6 @@ static int __devinit max17048_probe(struct i2c_client *client,
dev_err(&client->dev, "failed: power supply register\n");
goto error;
}
- max17048_reset(client);
INIT_DELAYED_WORK_DEFERRABLE(&chip->work, max17048_work);
schedule_delayed_work(&chip->work, MAX17048_DELAY);
diff --git a/include/linux/max17048_battery.h b/include/linux/max17048_battery.h
index f557b317be69..d997082fb5a9 100644
--- a/include/linux/max17048_battery.h
+++ b/include/linux/max17048_battery.h
@@ -10,6 +10,22 @@
#ifndef __MAX17048_BATTERY_H_
#define __MAX17048_BATTERY_H_
+#include <linux/smb349-charger.h>
+
+struct max17048_battery_model {
+ uint8_t rcomp;
+ uint8_t soccheck_A;
+ uint8_t soccheck_B;
+ uint8_t bits;
+ uint8_t alert_threshold;
+ uint8_t one_percent_alerts;
+ uint8_t alert_on_reset;
+ uint16_t rcomp_seg;
+ uint16_t hibernate;
+ uint16_t vreset;
+ uint16_t valert;
+ uint16_t ocvtest;
+};
struct max17048_platform_data {
int (*battery_online)(void);