summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorHyongbin Kim <hyongbink@nvidia.com>2013-07-15 15:09:26 +0900
committerGabby Lee <galee@nvidia.com>2013-08-23 04:47:14 -0700
commit4c00c119bfbf79385da16ed228ce0125b4d9c43a (patch)
treea1ef7f2932f285669429975ffba657673aa1d2e0 /drivers
parent2ea3fa785bf8d8fe753fa7653b6a5b46eb864f3e (diff)
power: max17048: set current threshold at low SOC
Support current threshold table for prevent sudden power off or freeze under low SOC. Bug 1304204 Bug 1316595 Change-Id: I4374c27a781a96d3f5b6a3f59af2ce3dcd55bbf3 Signed-off-by: Hyongbin Kim <hyongbink@nvidia.com> Reviewed-on: http://git-master/r/249079 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Gabby Lee <galee@nvidia.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/power/max17048_battery.c104
1 files changed, 103 insertions, 1 deletions
diff --git a/drivers/power/max17048_battery.c b/drivers/power/max17048_battery.c
index 6c6c1c5b0cf9..e851a1dde911 100644
--- a/drivers/power/max17048_battery.c
+++ b/drivers/power/max17048_battery.c
@@ -26,6 +26,7 @@
#include <linux/jiffies.h>
#include <linux/wakelock.h>
#include <linux/thermal.h>
+#include <linux/platform_data/ina230.h>
#include <generated/mach-types.h>
#define MAX17048_VCELL 0x02
@@ -81,12 +82,14 @@ struct max17048_chip {
int capacity_level;
/* battery temperature */
long temperature;
+ /* current threshold */
+ int current_threshold;
int internal_soc;
int lasttime_soc;
int lasttime_status;
long lasttime_temperature;
-
+ int lasttime_current_threshold;
int shutdown_complete;
struct mutex mutex;
struct wake_lock wake_lock;
@@ -280,6 +283,54 @@ static void max17048_get_soc(struct i2c_client *client)
}
}
+static void max17048_set_current_threshold(struct i2c_client *client)
+{
+ struct max17048_chip *chip = i2c_get_clientdata(client);
+ s32 ret;
+ int min_cpu;
+ int i;
+
+ /* current threshold by SOC */
+ /* current_threshold arrays should be sorted in ascending order */
+ if (chip->pdata->set_current_threshold &&
+ chip->pdata->current_threshold_num &&
+ chip->pdata->current_normal) {
+
+ min_cpu = 2;
+ chip->current_threshold = chip->pdata->current_normal;
+
+ for (i = 0; i < chip->pdata->current_threshold_num; i++) {
+ if ((chip->internal_soc <=
+ chip->pdata->current_threshold_soc[i]) &&
+ chip->pdata->current_threshold[i]) {
+ chip->current_threshold =
+ chip->pdata->current_threshold[i];
+ /* prevent current monitor power down */
+ min_cpu = 1;
+ break;
+ }
+ }
+
+ if (chip->current_threshold !=
+ chip->lasttime_current_threshold) {
+ ret = chip->pdata->
+ set_current_threshold(
+ chip->current_threshold, min_cpu);
+ if (ret < 0)
+ dev_err(&client->dev,
+ "%s: set current threshold err\n",
+ __func__);
+ else {
+ dev_info(&client->dev,
+ "%s(): set current threshold %d mA\n",
+ __func__, chip->current_threshold);
+ chip->lasttime_current_threshold =
+ chip->current_threshold;
+ }
+ }
+ }
+}
+
static uint16_t max17048_get_version(struct i2c_client *client)
{
return max17048_read_word(client, MAX17048_VER);
@@ -380,6 +431,7 @@ static void max17048_work(struct work_struct *work)
max17048_get_vcell(chip->client);
max17048_get_soc(chip->client);
+ max17048_set_current_threshold(chip->client);
if (chip->soc != chip->lasttime_soc ||
chip->status != chip->lasttime_status) {
@@ -680,6 +732,8 @@ static irqreturn_t max17048_irq(int id, void *dev)
if (val & MAX17048_STATUS_SC) {
max17048_get_vcell(client);
max17048_get_soc(client);
+ max17048_set_current_threshold(client);
+
chip->lasttime_soc = chip->soc;
dev_info(&client->dev,
"%s(): STATUS_SC, VCELL %dmV, SOC %d%%\n",
@@ -726,6 +780,8 @@ static struct max17048_platform_data *max17048_parse_dt(struct device *dev)
struct max17048_battery_model *model_data;
struct device_node *np = dev->of_node;
u32 val, val_array[MAX17048_DATA_SIZE];
+ u32 soc_array[MAX17048_MAX_SOC_STEP];
+ const char *str;
int i, ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
@@ -831,6 +887,47 @@ static struct max17048_platform_data *max17048_parse_dt(struct device *dev)
for (i = 0; i < MAX17048_DATA_SIZE; i++)
model_data->data_tbl[i] = val_array[i];
+ if ((!of_property_read_string(np, "set_current_threshold", &str)) &&
+ (!strncmp(str, "ina230", strlen(str)))) {
+ pdata->set_current_threshold = ina230_set_current_threshold;
+ } else {
+ pdata->set_current_threshold = NULL;
+ }
+
+ ret = of_property_read_u32(np, "current_normal", &val);
+ if (ret < 0)
+ pdata->current_normal = 0;
+ else
+ pdata->current_normal = val;
+
+ ret = of_property_read_u32(np, "current_threshold_num", &val);
+ if (ret < 0)
+ pdata->current_threshold_num = 0;
+ else
+ pdata->current_threshold_num = val;
+
+ if (pdata->current_threshold_num > MAX17048_MAX_SOC_STEP)
+ pdata->current_threshold_num = MAX17048_MAX_SOC_STEP;
+
+ if (pdata->set_current_threshold != NULL &&
+ pdata->current_normal &&
+ pdata->current_threshold_num) {
+ ret = of_property_read_u32_array(np, "current_threshold_soc",
+ soc_array, pdata->current_threshold_num);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ for (i = 0; i < pdata->current_threshold_num; i++)
+ pdata->current_threshold_soc[i] = soc_array[i];
+
+ ret = of_property_read_u32_array(np, "current_threshold",
+ soc_array, pdata->current_threshold_num);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ for (i = 0; i < pdata->current_threshold_num; i++)
+ pdata->current_threshold[i] = soc_array[i];
+ }
return pdata;
}
#else
@@ -888,6 +985,11 @@ static int __devinit max17048_probe(struct i2c_client *client,
chip->status = POWER_SUPPLY_STATUS_DISCHARGING;
chip->lasttime_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ if (chip->pdata->current_normal) {
+ chip->current_threshold = chip->pdata->current_normal;
+ chip->lasttime_current_threshold = chip->pdata->current_normal;
+ }
+
ret = power_supply_register(&client->dev, &chip->battery);
if (ret) {
dev_err(&client->dev, "failed: power supply register\n");