aboutsummaryrefslogtreecommitdiff
path: root/drivers/power
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/power')
-rwxr-xr-xdrivers/power/bq27541_battery.c18
-rwxr-xr-xdrivers/power/smb347-charger.c2
-rw-r--r--drivers/power/tps80031-charger.c110
3 files changed, 101 insertions, 29 deletions
diff --git a/drivers/power/bq27541_battery.c b/drivers/power/bq27541_battery.c
index 217e53a1f01..eb3e797c248 100755
--- a/drivers/power/bq27541_battery.c
+++ b/drivers/power/bq27541_battery.c
@@ -147,6 +147,7 @@ static enum power_supply_property bq27541_properties[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_CURRENT_NOW,
@@ -480,11 +481,11 @@ int battery_callback(unsigned usb_cable_state)
#endif
}
#ifndef REMOVE_USB_POWER_SUPPLY
- else if (battery_cable_status == USB_Cable) {
+ else if (battery_cable_status == USB_Cable && old_cable_status != USB_Cable) {
power_supply_changed(&bq27541_supply[Charger_Type_USB]);
}
#endif
- else if (battery_cable_status == USB_AC_Adapter) {
+ else if (battery_cable_status == USB_AC_Adapter && old_cable_status != USB_AC_Adapter) {
power_supply_changed(&bq27541_supply[Charger_Type_AC]);
}
cancel_delayed_work(&bq27541_device->status_poll_work);
@@ -550,6 +551,19 @@ static int bq27541_get_psp(int reg_offset, enum power_supply_property psp,
}
BAT_NOTICE("voltage_now= %u uV\n", val->intval);
}
+ if (psp == POWER_SUPPLY_PROP_CURRENT_NOW) {
+ val->intval = rt_value;
+ /* Returns a signed 16-bit value in mA */
+ if (val->intval & 0x8000) {
+ /* Negative */
+ val->intval = ~val->intval & 0x7fff;
+ val->intval++;
+ val->intval *= -1;
+ }
+ val->intval *= 1000;
+ BAT_NOTICE("current_now= %d uA\n", val->intval);
+ }
+
if (psp == POWER_SUPPLY_PROP_STATUS) {
ret = bq27541_device->bat_status = rt_value;
static char *status_text[] = {"Unknown", "Charging", "Discharging", "Not charging", "Full"};
diff --git a/drivers/power/smb347-charger.c b/drivers/power/smb347-charger.c
index 99ca790811f..6100b2b80c2 100755
--- a/drivers/power/smb347-charger.c
+++ b/drivers/power/smb347-charger.c
@@ -447,6 +447,8 @@ static int smb347_pin_control(bool state)
struct i2c_client *client = charger->client;
u8 ret = 0;
+ mutex_lock(&charger->pinctrl_lock);
+
printk("smb347_charger_enable %d\n",state);
if (state) {
/*Pin Controls -active low */
diff --git a/drivers/power/tps80031-charger.c b/drivers/power/tps80031-charger.c
index 93b283e0b04..9190b7201fd 100644
--- a/drivers/power/tps80031-charger.c
+++ b/drivers/power/tps80031-charger.c
@@ -3,7 +3,7 @@
*
* Battery charger driver for TI's tps80031
*
- * Copyright (c) 2011, NVIDIA Corporation.
+ * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
*
* 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
@@ -65,18 +65,41 @@ struct tps80031_charger {
};
static struct tps80031_charger *charger_data;
-static uint8_t charging_current_val_code[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0x27,
- 0x37, 0x28, 0x38, 0x29, 0x39, 0x2A, 0x3A, 0x2B, 0x3B, 0x2C,
- 0x3C, 0x2D, 0x3D, 0x2E,
+
+static uint8_t tps80031_get_vbus_input_current_limit_code(int max_uA)
+{
+ const uint8_t current_to_code[] = {
+ 0x0, /* 0 - 50 mA */
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, /* 50, 100, ..., 300mA */
+ 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, /* 350, 400, ..., 600mA */
+ 0xC, 0xD, 0xE, 0x27, 0x37, 0x28, /* 650, 700, ..., 900mA */
+ 0x38, 0x29, 0x39, 0x2A, 0x3A, 0x2B, /* 950, 700, ..., 1200mA */
+ 0x3B, 0x2C, 0x3C, 0x2D, 0x3D, 0x2E, /* 1200,1250, ..., 1500mA */
+ };
+ int charge_mA;
+ uint8_t code;
+
+ charge_mA = max_uA / 1000;
+ if (charge_mA < 0)
+ BUG();
+ else if (charge_mA < 1800)
+ code = current_to_code[charge_mA / 50];
+ else if (charge_mA < 2100)
+ code = 0x20; /* use 1800mA code */
+ else if (charge_mA < 2250)
+ code = 0x21; /* use 2100mA code */
+ else
+ code = 0x22; /* use 2250mA code */
+
+ return code;
};
static int set_charge_current_limit(struct regulator_dev *rdev,
int min_uA, int max_uA)
{
struct tps80031_charger *charger = rdev_get_drvdata(rdev);
- int max_vbus_current = 1500;
int max_charge_current = 1500;
+ uint8_t code;
int ret;
dev_info(charger->dev, "%s(): Min curr %dmA and max current %dmA\n",
@@ -101,13 +124,9 @@ static int set_charge_current_limit(struct regulator_dev *rdev,
return ret;
}
- max_vbus_current = min(max_uA/1000, max_vbus_current);
- max_vbus_current = max_vbus_current/50;
- if (max_vbus_current)
- max_vbus_current--;
+ code = tps80031_get_vbus_input_current_limit_code(max_uA);
ret = tps80031_update(charger->dev->parent, SLAVE_ID2,
- CHARGERUSB_CINLIMIT,
- charging_current_val_code[max_vbus_current], 0x3F);
+ CHARGERUSB_CINLIMIT, code, 0x3F);
if (ret < 0) {
dev_err(charger->dev, "%s(): Failed in writing register 0x%02x\n",
__func__, CHARGERUSB_CINLIMIT);
@@ -250,7 +269,8 @@ static int configure_charging_parameter(struct tps80031_charger *charger)
}
/* set Pre Charge current to 400mA */
- ret = tps80031_write(charger->dev->parent, SLAVE_ID2, 0xDE, 0x3);
+ ret = tps80031_write(charger->dev->parent, SLAVE_ID2,
+ CHARGERUSB_VICHRG_PC, 0x3);
if (ret < 0) {
dev_err(charger->dev, "%s(): Failed in writing register 0x%02x\n",
__func__, 0xDD);
@@ -274,27 +294,41 @@ static int configure_charging_parameter(struct tps80031_charger *charger)
return 0;
}
-static irqreturn_t linch_status_isr(int irq, void *dev_id)
+static bool tps80031_check_charging_completed(struct tps80031_charger *charger)
{
- struct tps80031_charger *charger = dev_id;
- uint8_t linch_status;
int ret;
- dev_info(charger->dev, "%s() got called\n", __func__);
+ uint8_t linch_status;
ret = tps80031_read(charger->dev->parent, SLAVE_ID2,
LINEAR_CHRG_STS, &linch_status);
if (ret < 0) {
dev_err(charger->dev, "%s(): Failed in reading register 0x%02x\n",
__func__, LINEAR_CHRG_STS);
+ return false;
+ }
+
+ if (linch_status & 0x20) {
+ charger->state = charging_state_charging_completed;
+ ret = true;
} else {
- dev_info(charger->dev, "%s():The status of LINEAR_CHRG_STS is 0x%02x\n",
- __func__, linch_status);
- if (linch_status & 0x20) {
- charger->state = charging_state_charging_completed;
- if (charger->charger_cb)
- charger->charger_cb(charger->state,
+ charger->state = charging_state_charging_in_progress;
+ ret = false;
+ }
+
+ return ret;
+}
+
+static irqreturn_t linch_status_isr(int irq, void *dev_id)
+{
+ struct tps80031_charger *charger = dev_id;
+
+ dev_info(charger->dev, "%s() got called\n", __func__);
+
+ if (tps80031_check_charging_completed(charger)) {
+ charger->state = charging_state_charging_completed;
+ if (charger->charger_cb)
+ charger->charger_cb(charger->state,
charger->charger_cb_data);
- }
}
return IRQ_HANDLED;
@@ -306,8 +340,22 @@ static irqreturn_t watchdog_expire_isr(int irq, void *dev_id)
int ret;
dev_info(charger->dev, "%s()\n", __func__);
- if (charger->state != charging_state_charging_in_progress)
- return IRQ_HANDLED;
+ if (charger->state != charging_state_charging_in_progress) {
+ /*
+ * After the charge completed, the chip can enable the
+ * charging again if battery voltage is 120mV below the
+ * charging voltage (defined by VOREG register).
+ */
+ if (tps80031_check_charging_completed(charger)) {
+ return IRQ_HANDLED;
+ } else {
+ /* "recharging" after charging completed happened */
+ charger->state = charging_state_charging_in_progress;
+ if (charger->charger_cb)
+ charger->charger_cb(charger->state,
+ charger->charger_cb_data);
+ }
+ }
/* Enable watchdog timer again*/
ret = tps80031_write(charger->dev->parent, SLAVE_ID2, CONTROLLER_WDG,
@@ -333,10 +381,18 @@ static int tps80031_charger_probe(struct platform_device *pdev)
int ret = 0;
struct device *dev = &pdev->dev;
struct tps80031_charger *charger;
- struct tps80031_charger_platform_data *pdata = pdev->dev.platform_data;
+ struct tps80031_platform_data *tps80031_pdata;
+ struct tps80031_charger_platform_data *pdata;
dev_info(dev, "%s()\n", __func__);
+ tps80031_pdata = dev_get_platdata(pdev->dev.parent);
+ if (!tps80031_pdata) {
+ dev_err(&pdev->dev, "no tps80031 platform_data specified\n");
+ return -EINVAL;
+ }
+
+ pdata = tps80031_pdata->battery_charger_pdata;
if (!pdata) {
dev_err(dev, "%s() No platform data, exiting..\n", __func__);
return -ENODEV;