diff options
Diffstat (limited to 'drivers/power')
| -rwxr-xr-x | drivers/power/bq27541_battery.c | 18 | ||||
| -rwxr-xr-x | drivers/power/smb347-charger.c | 2 | ||||
| -rw-r--r-- | drivers/power/tps80031-charger.c | 110 |
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; |
