mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
Revert "msm: power: Revert LGE power patches"
This reverts commit 2f24cb771c
.
This commit is contained in:
parent
b8c65bc60a
commit
491b58e1ca
18 changed files with 1374 additions and 157 deletions
|
@ -488,7 +488,7 @@ apq8064_pm8xxx_ccadc_pdata = {
|
|||
|
||||
static struct pm8921_bms_platform_data
|
||||
apq8064_pm8921_bms_pdata __devinitdata = {
|
||||
.battery_type = BATT_UNKNOWN, //FIXME Define correct type
|
||||
.battery_type = BATT_LGE,
|
||||
.r_sense = 10,
|
||||
.v_cutoff = 3500,
|
||||
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
#define PM8018_REVISION_MASK 0x000F
|
||||
|
||||
#define REG_PM8018_PON_CNTRL_3 0x01D
|
||||
#define PM8018_RESTART_REASON_MASK 0x07
|
||||
|
||||
#define SINGLE_IRQ_RESOURCE(_name, _irq) \
|
||||
{ \
|
||||
|
@ -61,6 +60,7 @@ struct pm8018 {
|
|||
struct mfd_cell *mfd_regulators;
|
||||
struct pm8xxx_regulator_core_platform_data *regulator_cdata;
|
||||
u32 rev_registers;
|
||||
u8 restart_reason;
|
||||
};
|
||||
|
||||
static int pm8018_readb(const struct device *dev, u16 addr, u8 *val)
|
||||
|
@ -125,6 +125,14 @@ static int pm8018_get_revision(const struct device *dev)
|
|||
return pmic->rev_registers & PM8018_REVISION_MASK;
|
||||
}
|
||||
|
||||
static u8 pm8018_restart_reason(const struct device *dev)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8018_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8018 *pmic = pm8018_drvdata->pm_chip_data;
|
||||
|
||||
return pmic->restart_reason;
|
||||
}
|
||||
|
||||
static struct pm8xxx_drvdata pm8018_drvdata = {
|
||||
.pmic_readb = pm8018_readb,
|
||||
.pmic_writeb = pm8018_writeb,
|
||||
|
@ -133,6 +141,7 @@ static struct pm8xxx_drvdata pm8018_drvdata = {
|
|||
.pmic_read_irq_stat = pm8018_read_irq_stat,
|
||||
.pmic_get_version = pm8018_get_version,
|
||||
.pmic_get_revision = pm8018_get_revision,
|
||||
.pmic_restart_reason = pm8018_restart_reason,
|
||||
};
|
||||
|
||||
static const struct resource gpio_cell_resources[] __devinitconst = {
|
||||
|
@ -516,17 +525,6 @@ bail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const char * const pm8018_restart_reason[] = {
|
||||
[0] = "Unknown",
|
||||
[1] = "Triggered from CBL (external charger)",
|
||||
[2] = "Triggered from KPD (power key press)",
|
||||
[3] = "Triggered from CHG (usb charger insertion)",
|
||||
[4] = "Triggered from SMPL (sudden momentary power loss)",
|
||||
[5] = "Triggered from RTC (real time clock)",
|
||||
[6] = "Triggered by Hard Reset",
|
||||
[7] = "Triggered by General Purpose Trigger",
|
||||
};
|
||||
|
||||
static const char * const pm8018_rev_names[] = {
|
||||
[PM8XXX_REVISION_8018_TEST] = "test",
|
||||
[PM8XXX_REVISION_8018_1p0] = "1.0",
|
||||
|
@ -594,8 +592,9 @@ static int __devinit pm8018_probe(struct platform_device *pdev)
|
|||
pr_err("Cannot read restart reason rc=%d\n", rc);
|
||||
goto err_read_rev;
|
||||
}
|
||||
val &= PM8018_RESTART_REASON_MASK;
|
||||
pr_info("PMIC Restart Reason: %s\n", pm8018_restart_reason[val]);
|
||||
val &= PM8XXX_RESTART_REASON_MASK;
|
||||
pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
|
||||
pmic->restart_reason = val;
|
||||
|
||||
rc = pm8018_add_subdevices(pdata, pmic);
|
||||
if (rc) {
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
#define PM8038_REVISION_MASK 0x000F
|
||||
|
||||
#define REG_PM8038_PON_CNTRL_3 0x01D
|
||||
#define PM8038_RESTART_REASON_MASK 0x07
|
||||
|
||||
#define SINGLE_IRQ_RESOURCE(_name, _irq) \
|
||||
{ \
|
||||
|
@ -65,6 +64,7 @@ struct pm8038 {
|
|||
struct mfd_cell *mfd_regulators;
|
||||
struct pm8xxx_regulator_core_platform_data *regulator_cdata;
|
||||
u32 rev_registers;
|
||||
u8 restart_reason;
|
||||
};
|
||||
|
||||
static int pm8038_readb(const struct device *dev, u16 addr, u8 *val)
|
||||
|
@ -129,6 +129,14 @@ static int pm8038_get_revision(const struct device *dev)
|
|||
return pmic->rev_registers & PM8038_REVISION_MASK;
|
||||
}
|
||||
|
||||
static u8 pm8038_restart_reason(const struct device *dev)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8038_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8038 *pmic = pm8038_drvdata->pm_chip_data;
|
||||
|
||||
return pmic->restart_reason;
|
||||
}
|
||||
|
||||
static struct pm8xxx_drvdata pm8038_drvdata = {
|
||||
.pmic_readb = pm8038_readb,
|
||||
.pmic_writeb = pm8038_writeb,
|
||||
|
@ -137,6 +145,7 @@ static struct pm8xxx_drvdata pm8038_drvdata = {
|
|||
.pmic_read_irq_stat = pm8038_read_irq_stat,
|
||||
.pmic_get_version = pm8038_get_version,
|
||||
.pmic_get_revision = pm8038_get_revision,
|
||||
.pmic_restart_reason = pm8038_restart_reason,
|
||||
};
|
||||
|
||||
static const struct resource gpio_cell_resources[] __devinitconst = {
|
||||
|
@ -723,17 +732,6 @@ bail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const char * const pm8038_restart_reason[] = {
|
||||
[0] = "Unknown",
|
||||
[1] = "Triggered from CBL (external charger)",
|
||||
[2] = "Triggered from KPD (power key press)",
|
||||
[3] = "Triggered from CHG (usb charger insertion)",
|
||||
[4] = "Triggered from SMPL (sudden momentary power loss)",
|
||||
[5] = "Triggered from RTC (real time clock)",
|
||||
[6] = "Triggered by Hard Reset",
|
||||
[7] = "Triggered by General Purpose Trigger",
|
||||
};
|
||||
|
||||
static const char * const pm8038_rev_names[] = {
|
||||
[PM8XXX_REVISION_8038_TEST] = "test",
|
||||
[PM8XXX_REVISION_8038_1p0] = "1.0",
|
||||
|
@ -802,8 +800,9 @@ static int __devinit pm8038_probe(struct platform_device *pdev)
|
|||
pr_err("Cannot read restart reason rc=%d\n", rc);
|
||||
goto err_read_rev;
|
||||
}
|
||||
val &= PM8038_RESTART_REASON_MASK;
|
||||
pr_info("PMIC Restart Reason: %s\n", pm8038_restart_reason[val]);
|
||||
val &= PM8XXX_RESTART_REASON_MASK;
|
||||
pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
|
||||
pmic->restart_reason = val;
|
||||
|
||||
rc = pm8038_add_subdevices(pdata, pmic);
|
||||
if (rc) {
|
||||
|
|
|
@ -63,6 +63,7 @@ struct pm8921 {
|
|||
struct mfd_cell *mfd_regulators;
|
||||
struct pm8xxx_regulator_core_platform_data *regulator_cdata;
|
||||
u32 rev_registers;
|
||||
u8 restart_reason;
|
||||
};
|
||||
|
||||
static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
|
||||
|
@ -133,6 +134,14 @@ static int pm8921_get_revision(const struct device *dev)
|
|||
return pmic->rev_registers & PM8921_REVISION_MASK;
|
||||
}
|
||||
|
||||
static u8 pm8921_restart_reason(const struct device *dev)
|
||||
{
|
||||
const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
|
||||
const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
|
||||
|
||||
return pmic->restart_reason;
|
||||
}
|
||||
|
||||
static struct pm8xxx_drvdata pm8921_drvdata = {
|
||||
.pmic_readb = pm8921_readb,
|
||||
.pmic_writeb = pm8921_writeb,
|
||||
|
@ -141,6 +150,7 @@ static struct pm8xxx_drvdata pm8921_drvdata = {
|
|||
.pmic_read_irq_stat = pm8921_read_irq_stat,
|
||||
.pmic_get_version = pm8921_get_version,
|
||||
.pmic_get_revision = pm8921_get_revision,
|
||||
.pmic_restart_reason = pm8921_restart_reason,
|
||||
};
|
||||
|
||||
static struct resource gpio_cell_resources[] = {
|
||||
|
@ -612,6 +622,18 @@ pm8921_add_subdevices(const struct pm8921_platform_data *pdata,
|
|||
}
|
||||
}
|
||||
|
||||
if (pdata->pwrkey_pdata) {
|
||||
pwrkey_cell.platform_data = pdata->pwrkey_pdata;
|
||||
pwrkey_cell.pdata_size =
|
||||
sizeof(struct pm8xxx_pwrkey_platform_data);
|
||||
ret = mfd_add_devices(pmic->dev, 0, &pwrkey_cell, 1, NULL,
|
||||
irq_base);
|
||||
if (ret) {
|
||||
pr_err("Failed to add pwrkey subdevice ret=%d\n", ret);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->mpp_pdata) {
|
||||
if (version == PM8XXX_VERSION_8917) {
|
||||
mpp_cell_resources[0].end = mpp_cell_resources[0].end
|
||||
|
@ -643,18 +665,6 @@ pm8921_add_subdevices(const struct pm8921_platform_data *pdata,
|
|||
}
|
||||
}
|
||||
|
||||
if (pdata->pwrkey_pdata) {
|
||||
pwrkey_cell.platform_data = pdata->pwrkey_pdata;
|
||||
pwrkey_cell.pdata_size =
|
||||
sizeof(struct pm8xxx_pwrkey_platform_data);
|
||||
ret = mfd_add_devices(pmic->dev, 0, &pwrkey_cell, 1, NULL,
|
||||
irq_base);
|
||||
if (ret) {
|
||||
pr_err("Failed to add pwrkey subdevice ret=%d\n", ret);
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
if (pdata->keypad_pdata) {
|
||||
keypad_cell.platform_data = pdata->keypad_pdata;
|
||||
keypad_cell.pdata_size =
|
||||
|
@ -815,17 +825,6 @@ bail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static const char * const pm8921_restart_reason[] = {
|
||||
[0] = "Unknown",
|
||||
[1] = "Triggered from CBL (external charger)",
|
||||
[2] = "Triggered from KPD (power key press)",
|
||||
[3] = "Triggered from CHG (usb charger insertion)",
|
||||
[4] = "Triggered from SMPL (sudden momentary power loss)",
|
||||
[5] = "Triggered from RTC (real time clock)",
|
||||
[6] = "Triggered by Hard Reset",
|
||||
[7] = "Triggered by General Purpose Trigger",
|
||||
};
|
||||
|
||||
static const char * const pm8921_rev_names[] = {
|
||||
[PM8XXX_REVISION_8921_TEST] = "test",
|
||||
[PM8XXX_REVISION_8921_1p0] = "1.0",
|
||||
|
@ -918,8 +917,9 @@ static int __devinit pm8921_probe(struct platform_device *pdev)
|
|||
pr_err("Cannot read restart reason rc=%d\n", rc);
|
||||
goto err_read_rev;
|
||||
}
|
||||
val &= PM8921_RESTART_REASON_MASK;
|
||||
pr_info("PMIC Restart Reason: %s\n", pm8921_restart_reason[val]);
|
||||
val &= PM8XXX_RESTART_REASON_MASK;
|
||||
pr_info("PMIC Restart Reason: %s\n", pm8xxx_restart_reason_str[val]);
|
||||
pmic->restart_reason = val;
|
||||
|
||||
rc = pm8921_add_subdevices(pdata, pmic);
|
||||
if (rc) {
|
||||
|
|
|
@ -435,4 +435,23 @@ config AB8500_BATTERY_THERM_ON_BATCTRL
|
|||
Say Y to enable battery temperature measurements using
|
||||
thermistor connected on BATCTRL ADC.
|
||||
|
||||
config WIRELESS_CHARGER
|
||||
bool "Wireless Charger Configuration"
|
||||
default n
|
||||
help
|
||||
wireless charger configuration
|
||||
|
||||
config BQ51051B_CHARGER
|
||||
bool "TI BQ51051B Wireless Charging control Driver"
|
||||
depends on WIRELESS_CHARGER
|
||||
help
|
||||
TI BQ51051B wireless charging control driver
|
||||
|
||||
config BATTERY_TEMP_CONTROL
|
||||
default n
|
||||
bool "Battery Temperature Control Configuration"
|
||||
help
|
||||
Say Y to enable battery temperature control for safty.
|
||||
It controls charging current depending on battery temperature.
|
||||
|
||||
endif # POWER_SUPPLY
|
||||
|
|
|
@ -58,3 +58,5 @@ obj-$(CONFIG_PM8921_BMS) += pm8921-bms.o
|
|||
obj-$(CONFIG_PM8921_CHARGER) += pm8921-charger.o
|
||||
obj-$(CONFIG_LTC4088_CHARGER) += ltc4088-charger.o
|
||||
obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
|
||||
obj-$(CONFIG_BQ51051B_CHARGER) += bq51051b_charger.o
|
||||
obj-$(CONFIG_BATTERY_TEMP_CONTROL) += battery_temp_ctrl.o
|
||||
|
|
281
drivers/power/battery_temp_ctrl.c
Normal file
281
drivers/power/battery_temp_ctrl.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright(c) 2012, LG Electronics Inc. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/platform_data/battery_temp_ctrl.h>
|
||||
|
||||
struct batt_temp_chip {
|
||||
struct delayed_work monitor_work;
|
||||
struct batt_temp_pdata *pdata;
|
||||
};
|
||||
|
||||
#define INIT_VAL 1000
|
||||
static int fake_temp = INIT_VAL;
|
||||
static ssize_t batt_temp_fake_temp_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int level;
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
level = simple_strtoul(buf, NULL, 10);
|
||||
if (level > 1000)
|
||||
fake_temp = 1000-level;
|
||||
else
|
||||
fake_temp = level;
|
||||
|
||||
pr_info("%s: fake_temp = %d\n", __func__, fake_temp);
|
||||
return count;
|
||||
}
|
||||
DEVICE_ATTR(fake_temp, 0664, NULL, batt_temp_fake_temp_store);
|
||||
|
||||
static int determin_batt_temp_state(struct batt_temp_pdata *pdata,
|
||||
int batt_temp, int batt_mvolt)
|
||||
{
|
||||
static int temp_state = TEMP_LEVEL_NORMAL;
|
||||
|
||||
if (pdata->is_ext_power()) {
|
||||
pr_debug("%s : is_ext_power = true\n", __func__);
|
||||
|
||||
if (batt_temp >= pdata->temp_level[TEMP_LEVEL_POWER_OFF]) {
|
||||
temp_state = TEMP_LEVEL_POWER_OFF;
|
||||
} else if (batt_temp >= pdata->temp_level[TEMP_LEVEL_HOT_STOPCHARGING]) {
|
||||
temp_state = TEMP_LEVEL_HOT_STOPCHARGING;
|
||||
} else if (batt_temp >= pdata->temp_level[TEMP_LEVEL_DECREASING]) {
|
||||
if (batt_mvolt > pdata->thr_mvolt
|
||||
|| temp_state == TEMP_LEVEL_HOT_STOPCHARGING)
|
||||
temp_state = TEMP_LEVEL_HOT_STOPCHARGING;
|
||||
else
|
||||
temp_state = TEMP_LEVEL_DECREASING;
|
||||
} else if (batt_temp > pdata->temp_level[TEMP_LEVEL_HOT_RECHARGING]) {
|
||||
if (temp_state == TEMP_LEVEL_HOT_STOPCHARGING
|
||||
|| temp_state == TEMP_LEVEL_DECREASING)
|
||||
temp_state = TEMP_LEVEL_HOT_STOPCHARGING;
|
||||
else if (temp_state == TEMP_LEVEL_DECREASING)
|
||||
temp_state = TEMP_LEVEL_DECREASING;
|
||||
else
|
||||
temp_state = TEMP_LEVEL_NORMAL;
|
||||
} else if (batt_temp >= pdata->temp_level[TEMP_LEVEL_COLD_RECHARGING]) {
|
||||
if (temp_state == TEMP_LEVEL_HOT_STOPCHARGING
|
||||
|| temp_state == TEMP_LEVEL_DECREASING)
|
||||
temp_state = TEMP_LEVEL_HOT_RECHARGING;
|
||||
else if (temp_state == TEMP_LEVEL_COLD_STOPCHARGING)
|
||||
temp_state = TEMP_LEVEL_COLD_RECHARGING;
|
||||
else
|
||||
temp_state = TEMP_LEVEL_NORMAL;
|
||||
} else if (batt_temp <= pdata->temp_level[TEMP_LEVEL_COLD_STOPCHARGING]) {
|
||||
temp_state = TEMP_LEVEL_COLD_STOPCHARGING;
|
||||
} else if (batt_temp < pdata->temp_level[TEMP_LEVEL_COLD_RECHARGING]) {
|
||||
if (temp_state == TEMP_LEVEL_COLD_STOPCHARGING)
|
||||
temp_state = TEMP_LEVEL_COLD_STOPCHARGING;
|
||||
else
|
||||
temp_state = TEMP_LEVEL_NORMAL;
|
||||
} else if (batt_temp <= pdata->temp_level[TEMP_LEVEL_HOT_RECHARGING]) {
|
||||
if (temp_state == TEMP_LEVEL_HOT_STOPCHARGING)
|
||||
temp_state = TEMP_LEVEL_HOT_RECHARGING;
|
||||
else if (temp_state == TEMP_LEVEL_COLD_STOPCHARGING)
|
||||
temp_state = TEMP_LEVEL_COLD_RECHARGING;
|
||||
else
|
||||
temp_state = TEMP_LEVEL_NORMAL;
|
||||
} else {
|
||||
temp_state = TEMP_LEVEL_NORMAL;
|
||||
}
|
||||
} else {
|
||||
pr_debug("%s : is_ext_power = false\n", __func__);
|
||||
|
||||
if (batt_temp >= pdata->temp_level[TEMP_LEVEL_POWER_OFF])
|
||||
temp_state = TEMP_LEVEL_POWER_OFF;
|
||||
else if (batt_temp >= pdata->temp_level[TEMP_LEVEL_WARNINGOVERHEAT])
|
||||
temp_state = TEMP_LEVEL_WARNINGOVERHEAT;
|
||||
else
|
||||
temp_state = TEMP_LEVEL_NORMAL;
|
||||
}
|
||||
|
||||
return temp_state;
|
||||
}
|
||||
|
||||
static void batt_temp_monitor_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dwork = to_delayed_work(work);
|
||||
struct batt_temp_chip *chip = container_of(dwork,
|
||||
struct batt_temp_chip, monitor_work);
|
||||
struct batt_temp_pdata *pdata = chip->pdata;
|
||||
static struct power_supply *psy = NULL;
|
||||
int batt_temp = 0;
|
||||
int batt_mvolt = 0;
|
||||
int temp_state = TEMP_LEVEL_NORMAL;
|
||||
static int temp_old_state = TEMP_LEVEL_NORMAL;
|
||||
union power_supply_propval ret = {0,};
|
||||
int rc;
|
||||
|
||||
if (!psy) {
|
||||
psy = power_supply_get_by_name("battery");
|
||||
if (!psy) {
|
||||
pr_err("%s: failed to get power supply\n", __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
rc = psy->get_property(psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &ret);
|
||||
if (rc) {
|
||||
pr_err("%s: failed to get voltage\n", __func__);
|
||||
return;
|
||||
}
|
||||
batt_mvolt = ret.intval/1000;
|
||||
|
||||
rc = psy->get_property(psy, POWER_SUPPLY_PROP_TEMP, &ret);
|
||||
if (rc) {
|
||||
pr_err("%s: failed to get temperature\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (fake_temp != INIT_VAL)
|
||||
batt_temp = fake_temp;
|
||||
else
|
||||
batt_temp = ret.intval;
|
||||
|
||||
temp_state = determin_batt_temp_state(pdata, batt_temp, batt_mvolt);
|
||||
pr_debug("%s: batt_temp = %d batt_mvolt = %d state = %d\n", __func__,
|
||||
batt_temp, batt_mvolt, temp_state);
|
||||
|
||||
switch (temp_state) {
|
||||
case TEMP_LEVEL_POWER_OFF:
|
||||
case TEMP_LEVEL_HOT_STOPCHARGING:
|
||||
case TEMP_LEVEL_COLD_STOPCHARGING:
|
||||
pr_info("%s: stop charging!! state = %d temp = %d mvolt = %d \n",
|
||||
__func__, temp_state, batt_temp, batt_mvolt);
|
||||
pdata->set_chg_i_limit(pdata->i_restore);
|
||||
pdata->disable_charging();
|
||||
pdata->set_health_state(POWER_SUPPLY_HEALTH_OVERHEAT, 0);
|
||||
break;
|
||||
case TEMP_LEVEL_WARNINGOVERHEAT:
|
||||
pdata->set_health_state(POWER_SUPPLY_HEALTH_OVERHEAT, 0);
|
||||
break;
|
||||
case TEMP_LEVEL_DECREASING:
|
||||
pr_info("%s: decrease current!! state = %d temp = %d mvolt = %d \n",
|
||||
__func__, temp_state, batt_temp, batt_mvolt);
|
||||
pdata->set_chg_i_limit(pdata->i_decrease);
|
||||
pdata->set_health_state(POWER_SUPPLY_HEALTH_GOOD,
|
||||
pdata->i_decrease);
|
||||
break;
|
||||
case TEMP_LEVEL_COLD_RECHARGING:
|
||||
case TEMP_LEVEL_HOT_RECHARGING:
|
||||
pr_info("%s: restart charging!! state = %d temp = %d mvolt = %d \n",
|
||||
__func__, temp_state, batt_temp, batt_mvolt);
|
||||
pdata->set_chg_i_limit(pdata->i_restore);
|
||||
pdata->enable_charging();
|
||||
pdata->set_health_state(POWER_SUPPLY_HEALTH_GOOD,
|
||||
pdata->i_restore);
|
||||
break;
|
||||
case TEMP_LEVEL_NORMAL:
|
||||
if (temp_old_state != TEMP_LEVEL_NORMAL) {
|
||||
pdata->set_chg_i_limit(pdata->i_restore);
|
||||
pdata->enable_charging();
|
||||
}
|
||||
pdata->set_health_state(POWER_SUPPLY_HEALTH_GOOD, 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
temp_old_state=temp_state;
|
||||
power_supply_changed(psy);
|
||||
schedule_delayed_work(&chip->monitor_work,
|
||||
round_jiffies_relative(msecs_to_jiffies(pdata->update_time)));
|
||||
|
||||
}
|
||||
|
||||
static int batt_temp_ctrl_suspend(struct device *dev)
|
||||
{
|
||||
struct batt_temp_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
cancel_delayed_work_sync(&chip->monitor_work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int batt_temp_ctrl_resume(struct device *dev)
|
||||
{
|
||||
struct batt_temp_chip *chip = dev_get_drvdata(dev);
|
||||
|
||||
schedule_delayed_work(&chip->monitor_work,
|
||||
round_jiffies_relative(msecs_to_jiffies
|
||||
(30000)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int batt_temp_ctrl_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct batt_temp_chip *chip;
|
||||
struct batt_temp_pdata *pdata = pdev->dev.platform_data;
|
||||
|
||||
pr_info("%s\n", __func__);
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("%s: no pdata\n", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip = kzalloc(sizeof(struct batt_temp_chip), GFP_KERNEL);
|
||||
if (!chip) {
|
||||
pr_err("%s: out of memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chip->pdata = pdata;
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
device_create_file(&pdev->dev, &dev_attr_fake_temp);
|
||||
|
||||
INIT_DELAYED_WORK(&chip->monitor_work,
|
||||
batt_temp_monitor_work);
|
||||
schedule_delayed_work(&chip->monitor_work,
|
||||
round_jiffies_relative(msecs_to_jiffies
|
||||
(pdata->update_time)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops batt_temp_ops = {
|
||||
.suspend = batt_temp_ctrl_suspend,
|
||||
.resume = batt_temp_ctrl_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver this_driver = {
|
||||
.probe = batt_temp_ctrl_probe,
|
||||
.driver = {
|
||||
.name = "batt_temp_ctrl",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &batt_temp_ops,
|
||||
},
|
||||
};
|
||||
|
||||
int __init batt_temp_ctrl_init(void)
|
||||
{
|
||||
pr_info("batt_temp_ctrl_init \n");
|
||||
return platform_driver_register(&this_driver);
|
||||
}
|
||||
|
||||
late_initcall(batt_temp_ctrl_init);
|
||||
|
||||
MODULE_DESCRIPTION("Battery Temperature Control Driver");
|
||||
MODULE_AUTHOR("ChoongRyeol Lee <choongryeol.lee@lge.com>");
|
||||
MODULE_LICENSE("GPL");
|
277
drivers/power/bq51051b_charger.c
Normal file
277
drivers/power/bq51051b_charger.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* BQ51051B Wireless Charging(WLC) control driver
|
||||
*
|
||||
* Copyright (C) 2012 LG Electronics, Inc
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/pm8xxx/pm8921.h>
|
||||
#include <linux/mfd/pm8xxx/pm8921-charger.h>
|
||||
#include <linux/mfd/pm8xxx/pm8921-bms.h>
|
||||
#include <linux/mfd/pm8xxx/core.h>
|
||||
#include <linux/leds-pm8xxx.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/power_supply.h>
|
||||
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/power/bq51051b_charger.h>
|
||||
|
||||
struct bq51051b_wlc_chip {
|
||||
struct device *dev;
|
||||
struct power_supply wireless_psy;
|
||||
struct work_struct wireless_interrupt_work;
|
||||
struct wake_lock wireless_chip_wake_lock;
|
||||
unsigned int active_n_gpio;
|
||||
int (*wlc_is_plugged)(void);
|
||||
};
|
||||
|
||||
static const struct platform_device_id bq51051b_id[] = {
|
||||
{BQ51051B_WLC_DEV_NAME, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct bq51051b_wlc_chip *the_chip;
|
||||
static bool wireless_charging;
|
||||
static bool wireless_charge_done;
|
||||
|
||||
static void bms_notify(struct bq51051b_wlc_chip *chip, int value)
|
||||
{
|
||||
if (value)
|
||||
pm8921_bms_charging_began();
|
||||
else
|
||||
pm8921_bms_charging_end(0);
|
||||
}
|
||||
|
||||
static enum power_supply_property pm_power_props_wireless[] = {
|
||||
POWER_SUPPLY_PROP_PRESENT,
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
};
|
||||
|
||||
static char *pm_power_supplied_to[] = {
|
||||
"battery",
|
||||
};
|
||||
|
||||
static int pm_power_get_property_wireless(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
/* Check if called before init */
|
||||
if (!the_chip)
|
||||
return -EINVAL;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
val->intval = 1; //always battery_on
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = wireless_charging;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wireless_set(struct bq51051b_wlc_chip *chip)
|
||||
{
|
||||
WLC_DBG_INFO("wireless_set\n");
|
||||
|
||||
wake_lock(&chip->wireless_chip_wake_lock);
|
||||
|
||||
wireless_charging = true;
|
||||
wireless_charge_done = false;
|
||||
|
||||
bms_notify(chip, 1);
|
||||
|
||||
power_supply_changed(&chip->wireless_psy);
|
||||
set_wireless_power_supply_control(wireless_charging);
|
||||
}
|
||||
|
||||
static void wireless_reset(struct bq51051b_wlc_chip *chip)
|
||||
{
|
||||
WLC_DBG_INFO("wireless_reset\n");
|
||||
|
||||
wireless_charging = false;
|
||||
wireless_charge_done = false;
|
||||
|
||||
bms_notify(chip, 0);
|
||||
|
||||
power_supply_changed(&chip->wireless_psy);
|
||||
set_wireless_power_supply_control(wireless_charging);
|
||||
|
||||
wake_unlock(&chip->wireless_chip_wake_lock);
|
||||
}
|
||||
|
||||
static void wireless_interrupt_worker(struct work_struct *work)
|
||||
{
|
||||
struct bq51051b_wlc_chip *chip =
|
||||
container_of(work, struct bq51051b_wlc_chip,
|
||||
wireless_interrupt_work);
|
||||
|
||||
if (chip->wlc_is_plugged())
|
||||
wireless_set(chip);
|
||||
else
|
||||
wireless_reset(chip);
|
||||
}
|
||||
|
||||
static irqreturn_t wireless_interrupt_handler(int irq, void *data)
|
||||
{
|
||||
int chg_state;
|
||||
struct bq51051b_wlc_chip *chip = data;
|
||||
|
||||
chg_state = chip->wlc_is_plugged();
|
||||
WLC_DBG_INFO("\nwireless is plugged state = %d\n\n", chg_state);
|
||||
schedule_work(&chip->wireless_interrupt_work);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int __devinit bq51051b_wlc_hw_init(struct bq51051b_wlc_chip *chip)
|
||||
{
|
||||
int ret;
|
||||
WLC_DBG_INFO("hw_init");
|
||||
|
||||
/* active_n pin must be monitoring the bq51051b status */
|
||||
ret = request_irq(gpio_to_irq(chip->active_n_gpio),
|
||||
wireless_interrupt_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"wireless_charger", chip);
|
||||
if (ret < 0) {
|
||||
pr_err("wlc: wireless_charger request irq failed\n");
|
||||
return ret;
|
||||
}
|
||||
enable_irq_wake(gpio_to_irq(chip->active_n_gpio));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq51051b_wlc_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bq51051b_wlc_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit bq51051b_wlc_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct bq51051b_wlc_chip *chip;
|
||||
const struct bq51051b_wlc_platform_data *pdata =
|
||||
pdev->dev.platform_data;
|
||||
|
||||
WLC_DBG_INFO("probe\n");
|
||||
|
||||
if (!pdata) {
|
||||
pr_err("wlc: missing platform data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
chip = kzalloc(sizeof(struct bq51051b_wlc_chip), GFP_KERNEL);
|
||||
if (!chip) {
|
||||
pr_err("wlc: Cannot allocate bq51051b_wlc_chip\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
chip->dev = &pdev->dev;
|
||||
|
||||
chip->active_n_gpio = pdata->active_n_gpio;
|
||||
chip->wlc_is_plugged = pdata->wlc_is_plugged;
|
||||
|
||||
rc = bq51051b_wlc_hw_init(chip);
|
||||
if (rc) {
|
||||
pr_err("wlc: couldn't init hardware rc = %d\n", rc);
|
||||
goto free_chip;
|
||||
}
|
||||
|
||||
chip->wireless_psy.name = "wireless";
|
||||
chip->wireless_psy.type = POWER_SUPPLY_TYPE_WIRELESS;
|
||||
chip->wireless_psy.supplied_to = pm_power_supplied_to;
|
||||
chip->wireless_psy.num_supplicants = ARRAY_SIZE(pm_power_supplied_to);
|
||||
chip->wireless_psy.properties = pm_power_props_wireless;
|
||||
chip->wireless_psy.num_properties = ARRAY_SIZE(pm_power_props_wireless);
|
||||
chip->wireless_psy.get_property = pm_power_get_property_wireless;
|
||||
|
||||
rc = power_supply_register(chip->dev, &chip->wireless_psy);
|
||||
if (rc < 0) {
|
||||
pr_err("wlc: power_supply_register wireless failed rx = %d\n",
|
||||
rc);
|
||||
goto free_chip;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, chip);
|
||||
the_chip = chip;
|
||||
|
||||
INIT_WORK(&chip->wireless_interrupt_work, wireless_interrupt_worker);
|
||||
wake_lock_init(&chip->wireless_chip_wake_lock, WAKE_LOCK_SUSPEND,
|
||||
"bq51051b_wireless_chip");
|
||||
|
||||
/* For Booting Wireless_charging and For Power Charging Logo In Wireless Charging */
|
||||
if (chip->wlc_is_plugged())
|
||||
wireless_set(chip);
|
||||
|
||||
return 0;
|
||||
|
||||
free_chip:
|
||||
kfree(chip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __devexit bq51051b_wlc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bq51051b_wlc_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
WLC_DBG_INFO("remove\n");
|
||||
wake_lock_destroy(&chip->wireless_chip_wake_lock);
|
||||
the_chip = NULL;
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
power_supply_unregister(&chip->wireless_psy);
|
||||
free_irq(gpio_to_irq(chip->active_n_gpio), chip);
|
||||
gpio_free(chip->active_n_gpio);
|
||||
kfree(chip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops bq51051b_pm_ops = {
|
||||
.suspend = bq51051b_wlc_suspend,
|
||||
.resume = bq51051b_wlc_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver bq51051b_wlc_driver = {
|
||||
.probe = bq51051b_wlc_probe,
|
||||
.remove = __devexit_p(bq51051b_wlc_remove),
|
||||
.id_table = bq51051b_id,
|
||||
.driver = {
|
||||
.name = BQ51051B_WLC_DEV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &bq51051b_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init bq51051b_wlc_init(void)
|
||||
{
|
||||
return platform_driver_register(&bq51051b_wlc_driver);
|
||||
}
|
||||
|
||||
static void __exit bq51051b_wlc_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bq51051b_wlc_driver);
|
||||
}
|
||||
|
||||
late_initcall(bq51051b_wlc_init);
|
||||
module_exit(bq51051b_wlc_exit);
|
||||
|
||||
MODULE_AUTHOR("Kyungtae Oh <Kyungtae.oh@lge.com>");
|
||||
MODULE_DESCRIPTION("BQ51051B Wireless Charger Control Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
|
||||
#include <linux/mfd/pm8xxx/pm8921-charger.h>
|
||||
#include <linux/mfd/pm8xxx/ccadc.h>
|
||||
#include <linux/power/bq51051b_charger.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
@ -54,6 +55,9 @@
|
|||
#define TEMP_IAVG_STORAGE 0x105
|
||||
#define TEMP_IAVG_STORAGE_USE_MASK 0x0F
|
||||
|
||||
#define PON_CNTRL_6 0x018
|
||||
#define WD_BIT BIT(7)
|
||||
|
||||
enum pmic_bms_interrupts {
|
||||
PM8921_BMS_SBI_WRITE_OK,
|
||||
PM8921_BMS_CC_THR,
|
||||
|
@ -134,7 +138,7 @@ struct pm8921_bms_chip {
|
|||
unsigned long tm_sec;
|
||||
int enable_fcc_learning;
|
||||
int shutdown_soc;
|
||||
int shutdown_iavg_ua;
|
||||
int shutdown_iavg_ma;
|
||||
struct delayed_work calculate_soc_delayed_work;
|
||||
struct timespec t_soc_queried;
|
||||
int shutdown_soc_valid_limit;
|
||||
|
@ -147,6 +151,16 @@ struct pm8921_bms_chip {
|
|||
int ibat_at_cv_ua;
|
||||
int soc_at_cv;
|
||||
int prev_chg_soc;
|
||||
int last_reported_soc;
|
||||
int eoc_check_soc;
|
||||
int soc_adjusted;
|
||||
int bms_support_wlc;
|
||||
int wlc_term_ua;
|
||||
int wlc_max_voltage_uv;
|
||||
int (*wlc_is_plugged)(void);
|
||||
int vbat_at_cv;
|
||||
int (*is_warm_reset)(void);
|
||||
int first_fixed_iavg_ma;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -157,7 +171,7 @@ static DEFINE_MUTEX(soc_invalidation_mutex);
|
|||
static int shutdown_soc_invalid;
|
||||
static struct pm8921_bms_chip *the_chip;
|
||||
|
||||
#define DEFAULT_RBATT_MOHMS 128
|
||||
#define DEFAULT_RBATT_MOHMS 200
|
||||
#define DEFAULT_OCV_MICROVOLTS 3900000
|
||||
#define DEFAULT_CHARGE_CYCLES 0
|
||||
|
||||
|
@ -346,13 +360,21 @@ static int pm_bms_masked_write(struct pm8921_bms_chip *chip, u16 addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int usb_chg_plugged_in(void)
|
||||
static int usb_chg_plugged_in(struct pm8921_bms_chip *chip)
|
||||
{
|
||||
int val = pm8921_is_usb_chg_plugged_in();
|
||||
|
||||
/* treat as if usb is not present in case of error */
|
||||
if (val == -EINVAL)
|
||||
val = 0;
|
||||
/* if the charger driver was not initialized, use the restart reason */
|
||||
if (val == -EINVAL) {
|
||||
if (pm8xxx_restart_reason(chip->dev->parent)
|
||||
== PM8XXX_RESTART_CHG)
|
||||
val = 1;
|
||||
else
|
||||
val = 0;
|
||||
}
|
||||
|
||||
if (chip->bms_support_wlc)
|
||||
val |= chip->wlc_is_plugged();
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -814,28 +836,26 @@ static int interpolate_ocv(struct pm8921_bms_chip *chip,
|
|||
}
|
||||
|
||||
static int interpolate_pc(struct pm8921_bms_chip *chip,
|
||||
int batt_temp, int ocv)
|
||||
int batt_temp_degc, int ocv)
|
||||
{
|
||||
int i, j, pcj, pcj_minus_one, pc;
|
||||
int rows = chip->pc_temp_ocv_lut->rows;
|
||||
int cols = chip->pc_temp_ocv_lut->cols;
|
||||
|
||||
/* batt_temp is in tenths of degC - convert it to degC for lookups */
|
||||
batt_temp = batt_temp/10;
|
||||
|
||||
if (batt_temp < chip->pc_temp_ocv_lut->temp[0]) {
|
||||
pr_debug("batt_temp %d < known temp range for pc\n", batt_temp);
|
||||
batt_temp = chip->pc_temp_ocv_lut->temp[0];
|
||||
if (batt_temp_degc < chip->pc_temp_ocv_lut->temp[0]) {
|
||||
pr_debug("batt_temp %d < known temp range\n", batt_temp_degc);
|
||||
batt_temp_degc = chip->pc_temp_ocv_lut->temp[0];
|
||||
}
|
||||
if (batt_temp > chip->pc_temp_ocv_lut->temp[cols - 1]) {
|
||||
pr_debug("batt_temp %d > known temp range for pc\n", batt_temp);
|
||||
batt_temp = chip->pc_temp_ocv_lut->temp[cols - 1];
|
||||
if (batt_temp_degc > chip->pc_temp_ocv_lut->temp[cols - 1]) {
|
||||
pr_debug("batt_temp %d > known temp range\n", batt_temp_degc);
|
||||
batt_temp_degc = chip->pc_temp_ocv_lut->temp[cols - 1];
|
||||
}
|
||||
|
||||
for (j = 0; j < cols; j++)
|
||||
if (batt_temp <= chip->pc_temp_ocv_lut->temp[j])
|
||||
if (batt_temp_degc <= chip->pc_temp_ocv_lut->temp[j])
|
||||
break;
|
||||
if (batt_temp == chip->pc_temp_ocv_lut->temp[j]) {
|
||||
if (batt_temp_degc == chip->pc_temp_ocv_lut->temp[j]) {
|
||||
/* found an exact match for temp in the table */
|
||||
if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
|
||||
return chip->pc_temp_ocv_lut->percent[0];
|
||||
|
@ -858,7 +878,7 @@ static int interpolate_pc(struct pm8921_bms_chip *chip,
|
|||
}
|
||||
|
||||
/*
|
||||
* batt_temp is within temperature for
|
||||
* batt_temp_degc is within temperature for
|
||||
* column j-1 and j
|
||||
*/
|
||||
if (ocv >= chip->pc_temp_ocv_lut->ocv[0][j])
|
||||
|
@ -898,7 +918,7 @@ static int interpolate_pc(struct pm8921_bms_chip *chip,
|
|||
chip->pc_temp_ocv_lut->temp[j-1],
|
||||
pcj,
|
||||
chip->pc_temp_ocv_lut->temp[j],
|
||||
batt_temp);
|
||||
batt_temp_degc);
|
||||
return pc;
|
||||
}
|
||||
}
|
||||
|
@ -910,7 +930,7 @@ static int interpolate_pc(struct pm8921_bms_chip *chip,
|
|||
return pcj_minus_one;
|
||||
|
||||
pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%",
|
||||
ocv, batt_temp);
|
||||
ocv, batt_temp_degc);
|
||||
return 100;
|
||||
}
|
||||
|
||||
|
@ -944,7 +964,7 @@ int override_mode_simultaneous_battery_voltage_and_current(int *ibat_ua,
|
|||
|
||||
mutex_unlock(&the_chip->bms_output_lock);
|
||||
|
||||
usb_chg = usb_chg_plugged_in();
|
||||
usb_chg = usb_chg_plugged_in(the_chip);
|
||||
|
||||
convert_vbatt_raw_to_uv(the_chip, usb_chg, vbat_raw, vbat_uv);
|
||||
convert_vsense_to_uv(the_chip, vsense_raw, &vsense_uv);
|
||||
|
@ -970,6 +990,40 @@ static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
|
|||
raw->last_good_ocv_raw -= MBG_TRANSIENT_ERROR_RAW;
|
||||
}
|
||||
|
||||
#define SEL_ALT_OREG_BIT BIT(2)
|
||||
static int ocv_ir_compensation(struct pm8921_bms_chip *chip, int ocv)
|
||||
{
|
||||
int compensated_ocv;
|
||||
int ibatt_ua;
|
||||
int rbatt_mohm = chip->default_rbatt_mohm + chip->rconn_mohm;
|
||||
|
||||
pm_bms_masked_write(chip, BMS_TEST1,
|
||||
SEL_ALT_OREG_BIT, SEL_ALT_OREG_BIT);
|
||||
|
||||
/* since the SEL_ALT_OREG_BIT is set this will give us VSENSE_OCV */
|
||||
pm8921_bms_get_battery_current(&ibatt_ua);
|
||||
compensated_ocv = ocv + div_s64((s64)ibatt_ua * rbatt_mohm, 1000);
|
||||
pr_info("comp ocv = %d, ocv = %d, ibatt_ua = %d, rbatt_mohm = %d\n",
|
||||
compensated_ocv, ocv, ibatt_ua, rbatt_mohm);
|
||||
|
||||
pm_bms_masked_write(chip, BMS_TEST1, SEL_ALT_OREG_BIT, 0);
|
||||
return compensated_ocv;
|
||||
}
|
||||
|
||||
static bool is_warm_restart(struct pm8921_bms_chip *chip)
|
||||
{
|
||||
u8 reg;
|
||||
int rc;
|
||||
|
||||
rc = pm8xxx_readb(chip->dev->parent, PON_CNTRL_6, ®);
|
||||
if (rc) {
|
||||
pr_err("err reading pon 6 rc = %d\n", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
return reg & WD_BIT;
|
||||
}
|
||||
|
||||
static int read_soc_params_raw(struct pm8921_bms_chip *chip,
|
||||
struct pm8921_soc_params *raw)
|
||||
{
|
||||
|
@ -985,14 +1039,22 @@ static int read_soc_params_raw(struct pm8921_bms_chip *chip,
|
|||
pm_bms_unlock_output_data(chip);
|
||||
mutex_unlock(&chip->bms_output_lock);
|
||||
|
||||
usb_chg = usb_chg_plugged_in();
|
||||
usb_chg = usb_chg_plugged_in(chip);
|
||||
|
||||
if (chip->prev_last_good_ocv_raw == 0) {
|
||||
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
|
||||
adjust_pon_ocv_raw(chip, raw);
|
||||
convert_vbatt_raw_to_uv(chip, usb_chg,
|
||||
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
|
||||
raw->last_good_ocv_uv = ocv_ir_compensation(chip,
|
||||
raw->last_good_ocv_uv);
|
||||
chip->last_ocv_uv = raw->last_good_ocv_uv;
|
||||
|
||||
if (is_warm_restart(chip)) {
|
||||
shutdown_soc_invalid = 1;
|
||||
pr_info("discard shutdown soc! cc_raw = 0x%x\n", raw->cc);
|
||||
}
|
||||
|
||||
pr_debug("PON_OCV_UV = %d\n", chip->last_ocv_uv);
|
||||
} else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
|
||||
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
|
||||
|
@ -1120,7 +1182,7 @@ static int calculate_pc(struct pm8921_bms_chip *chip, int ocv_uv, int batt_temp,
|
|||
{
|
||||
int pc, scalefactor;
|
||||
|
||||
pc = interpolate_pc(chip, batt_temp, ocv_uv / 1000);
|
||||
pc = interpolate_pc(chip, batt_temp / 10, ocv_uv / 1000);
|
||||
pr_debug("pc = %u for ocv = %dmicroVolts batt_temp = %d\n",
|
||||
pc, ocv_uv, batt_temp);
|
||||
|
||||
|
@ -1335,13 +1397,13 @@ static int calculate_unusable_charge_uah(struct pm8921_bms_chip *chip,
|
|||
|
||||
/*
|
||||
* if we are called first time fill all the
|
||||
* samples with the the shutdown_iavg_ua
|
||||
* samples with the the shutdown_iavg_ma
|
||||
*/
|
||||
if (firsttime && chip->shutdown_iavg_ua != 0) {
|
||||
pr_emerg("Using shutdown_iavg_ua = %d in all samples\n",
|
||||
chip->shutdown_iavg_ua);
|
||||
if (firsttime && chip->shutdown_iavg_ma != 0) {
|
||||
pr_emerg("Using shutdown_iavg_ma = %d in all samples\n",
|
||||
chip->shutdown_iavg_ma);
|
||||
for (i = 0; i < IAVG_SAMPLES; i++)
|
||||
iavg_samples[i] = chip->shutdown_iavg_ua;
|
||||
iavg_samples[i] = chip->shutdown_iavg_ma;
|
||||
|
||||
iavg_index = 0;
|
||||
iavg_num_samples = IAVG_SAMPLES;
|
||||
|
@ -1588,20 +1650,40 @@ static int charging_adjustments(struct pm8921_bms_chip *chip,
|
|||
int fcc_uah, int cc_uah, int uuc_uah)
|
||||
{
|
||||
int chg_soc;
|
||||
int max_vol;
|
||||
int eoc_current;
|
||||
|
||||
max_vol = chip->max_voltage_uv;
|
||||
eoc_current = -chip->chg_term_ua;
|
||||
|
||||
if (chip->bms_support_wlc && chip->wlc_is_plugged()) {
|
||||
max_vol = chip->wlc_max_voltage_uv;
|
||||
eoc_current = -chip->wlc_term_ua;
|
||||
}
|
||||
|
||||
if (chip->soc_at_cv == -EINVAL) {
|
||||
/* In constant current charging return the calc soc */
|
||||
if (vbat_uv <= chip->max_voltage_uv)
|
||||
if (vbat_uv <= max_vol)
|
||||
pr_debug("CC CHG SOC %d\n", soc);
|
||||
|
||||
/* Note the CC to CV point */
|
||||
if (vbat_uv >= chip->max_voltage_uv) {
|
||||
if (vbat_uv >= max_vol) {
|
||||
chip->soc_at_cv = soc;
|
||||
chip->prev_chg_soc = soc;
|
||||
chip->ibat_at_cv_ua = ibat_ua;
|
||||
chip->vbat_at_cv = vbat_uv;
|
||||
pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n",
|
||||
ibat_ua, soc);
|
||||
}
|
||||
else if(soc >= 95)
|
||||
{
|
||||
chip->soc_at_cv = soc;
|
||||
chip->prev_chg_soc = soc;
|
||||
chip->ibat_at_cv_ua = ibat_ua;
|
||||
chip->vbat_at_cv = vbat_uv;
|
||||
pr_debug("Force CC_TO_CV ibat_ua = %d CHG SOC %d\n",
|
||||
ibat_ua, soc);
|
||||
}
|
||||
return soc;
|
||||
}
|
||||
|
||||
|
@ -1614,15 +1696,25 @@ static int charging_adjustments(struct pm8921_bms_chip *chip,
|
|||
* if voltage lessened (possibly because of a system load)
|
||||
* keep reporting the prev chg soc
|
||||
*/
|
||||
if (vbat_uv <= chip->max_voltage_uv) {
|
||||
if (vbat_uv <= chip->vbat_at_cv) {
|
||||
pr_debug("vbat %d < max = %d CC CHG SOC %d\n",
|
||||
vbat_uv, chip->max_voltage_uv, chip->prev_chg_soc);
|
||||
vbat_uv, chip->vbat_at_cv, chip->prev_chg_soc);
|
||||
return chip->prev_chg_soc;
|
||||
}
|
||||
|
||||
if (chip->bms_support_wlc
|
||||
&& chip->wlc_is_plugged()
|
||||
&& chip->prev_chg_soc < 99
|
||||
&& ibat_ua > eoc_current) {
|
||||
pr_info("ibat < eco_current ! soc = %d \n", chip->prev_chg_soc);
|
||||
return chip->prev_chg_soc;
|
||||
}
|
||||
|
||||
chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua,
|
||||
100, -100000,
|
||||
100, eoc_current,
|
||||
ibat_ua);
|
||||
if (chg_soc > 100)
|
||||
chg_soc = 100;
|
||||
|
||||
/* always report a higher soc */
|
||||
if (chg_soc > chip->prev_chg_soc) {
|
||||
|
@ -1761,17 +1853,13 @@ static int adjust_soc(struct pm8921_bms_chip *chip, int soc,
|
|||
* soc = 0 should happen only when soc_est == 0
|
||||
*/
|
||||
if (soc_new == 0 && soc_est != 0)
|
||||
soc_new = 1;
|
||||
soc_new = 2;
|
||||
|
||||
soc = soc_new;
|
||||
|
||||
out:
|
||||
pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, "
|
||||
"soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, "
|
||||
"pc_new = %d, soc_new = %d, rbatt = %d, m = %d\n",
|
||||
ibat_ua, vbat_uv, ocv_est_uv, pc_est,
|
||||
soc_est, n, delta_ocv_uv, chip->last_ocv_uv,
|
||||
pc_new, soc_new, rbatt, m);
|
||||
pr_info("ibat_ua = %d, vbat_uv = %d, soc = %d, batt_temp=%d\n",
|
||||
ibat_ua, vbat_uv, soc, batt_temp);
|
||||
|
||||
return soc;
|
||||
}
|
||||
|
@ -1814,14 +1902,14 @@ static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
|
|||
if (rc) {
|
||||
pr_err("failed to read addr = %d %d assuming %d\n",
|
||||
TEMP_IAVG_STORAGE, rc, IAVG_START);
|
||||
chip->shutdown_iavg_ua = IAVG_START;
|
||||
chip->shutdown_iavg_ma = IAVG_START;
|
||||
} else {
|
||||
temp &= TEMP_IAVG_STORAGE_USE_MASK;
|
||||
|
||||
if (temp == 0) {
|
||||
chip->shutdown_iavg_ua = IAVG_START;
|
||||
chip->shutdown_iavg_ma = IAVG_START;
|
||||
} else {
|
||||
chip->shutdown_iavg_ua = IAVG_START
|
||||
chip->shutdown_iavg_ma = IAVG_START
|
||||
+ IAVG_STEP_SIZE_MA * (temp + 1);
|
||||
}
|
||||
}
|
||||
|
@ -1835,7 +1923,7 @@ static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
|
|||
if (chip->shutdown_soc == 0) {
|
||||
pr_debug("No shutdown soc available\n");
|
||||
shutdown_soc_invalid = 1;
|
||||
chip->shutdown_iavg_ua = 0;
|
||||
chip->shutdown_iavg_ma = 0;
|
||||
} else if (chip->shutdown_soc == SOC_ZERO) {
|
||||
chip->shutdown_soc = 0;
|
||||
}
|
||||
|
@ -1844,12 +1932,16 @@ static void read_shutdown_soc_and_iavg(struct pm8921_bms_chip *chip)
|
|||
if (chip->ignore_shutdown_soc) {
|
||||
shutdown_soc_invalid = 1;
|
||||
chip->shutdown_soc = 0;
|
||||
chip->shutdown_iavg_ua = 0;
|
||||
chip->shutdown_iavg_ma = 0;
|
||||
}
|
||||
|
||||
if (chip->first_fixed_iavg_ma && !chip->ignore_shutdown_soc) {
|
||||
chip->shutdown_iavg_ma = chip->first_fixed_iavg_ma;
|
||||
}
|
||||
|
||||
pr_debug("shutdown_soc = %d shutdown_iavg = %d shutdown_soc_invalid = %d\n",
|
||||
chip->shutdown_soc,
|
||||
chip->shutdown_iavg_ua,
|
||||
chip->shutdown_iavg_ma,
|
||||
shutdown_soc_invalid);
|
||||
}
|
||||
|
||||
|
@ -1918,6 +2010,45 @@ static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int is_eoc_adjust(struct pm8921_bms_chip *chip, int soc)
|
||||
{
|
||||
int batt_state = pm8921_get_batt_state();
|
||||
int ret = 0;
|
||||
|
||||
if (soc != 100)
|
||||
return 0;
|
||||
|
||||
switch (batt_state) {
|
||||
case POWER_SUPPLY_STATUS_CHARGING:
|
||||
if (chip->start_percent != -EINVAL
|
||||
&& chip->start_percent != 100)
|
||||
ret = 1;
|
||||
break;
|
||||
case POWER_SUPPLY_STATUS_DISCHARGING:
|
||||
case POWER_SUPPLY_STATUS_NOT_CHARGING:
|
||||
if (chip->soc_adjusted == 1)
|
||||
ret = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int is_recharging(struct pm8921_bms_chip *chip, int soc)
|
||||
{
|
||||
if (soc == -EINVAL)
|
||||
return 0;
|
||||
if ((pm8921_get_batt_state() == POWER_SUPPLY_STATUS_FULL)
|
||||
&& (soc < 100)
|
||||
&& (pm8921_get_batt_health()
|
||||
!= POWER_SUPPLY_HEALTH_OVERHEAT))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remaining Usable Charge = remaining_charge (charge at ocv instance)
|
||||
* - coloumb counter charge
|
||||
|
@ -2039,16 +2170,20 @@ static int calculate_state_of_charge(struct pm8921_bms_chip *chip,
|
|||
|
||||
chip->pon_ocv_uv = chip->last_ocv_uv;
|
||||
chip->last_ocv_uv = new_ocv;
|
||||
remaining_charge_uah = new_rc_uah;
|
||||
unusable_charge_uah = new_ucc_uah;
|
||||
rbatt = new_rbatt;
|
||||
|
||||
if ((new_rc_uah - remaining_charge_uah) > fcc_uah*5/100)
|
||||
remaining_charge_uah = new_rc_uah - fcc_uah*1/100;
|
||||
else
|
||||
remaining_charge_uah = new_rc_uah;
|
||||
|
||||
remaining_usable_charge_uah = remaining_charge_uah
|
||||
- cc_uah
|
||||
- unusable_charge_uah;
|
||||
|
||||
soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
|
||||
(fcc_uah - unusable_charge_uah));
|
||||
soc = (remaining_usable_charge_uah * 100)/
|
||||
(fcc_uah - unusable_charge_uah);
|
||||
|
||||
pr_debug("DONE for shutdown_soc = %d soc is %d, adjusted ocv to %duV\n",
|
||||
shutdown_soc, soc, chip->last_ocv_uv);
|
||||
|
@ -2090,6 +2225,13 @@ static void calculate_soc_work(struct work_struct *work)
|
|||
|
||||
soc = calculate_state_of_charge(chip, &raw,
|
||||
batt_temp, last_chargecycles);
|
||||
|
||||
if (chip->eoc_check_soc
|
||||
&& is_recharging(chip, chip->last_reported_soc)) {
|
||||
pm8921_force_start_charging();
|
||||
pr_info("Recharging is started\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&chip->last_ocv_uv_mutex);
|
||||
|
||||
schedule_delayed_work(&chip->calculate_soc_delayed_work,
|
||||
|
@ -2164,13 +2306,22 @@ static int report_state_of_charge(struct pm8921_bms_chip *chip)
|
|||
}
|
||||
|
||||
/* last_soc < soc ... scale and catch up */
|
||||
if (last_soc != -EINVAL && last_soc < soc && soc != 100)
|
||||
if (last_soc != -EINVAL && soc != 100
|
||||
&& (last_soc < soc || the_chip->start_percent != -EINVAL))
|
||||
soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
|
||||
|
||||
if (chip->eoc_check_soc && is_eoc_adjust(chip, soc)) {
|
||||
soc = soc - 1;
|
||||
chip->soc_adjusted = 1;
|
||||
} else {
|
||||
chip->soc_adjusted = 0;
|
||||
}
|
||||
|
||||
last_soc = soc;
|
||||
backup_soc_and_iavg(chip, batt_temp, last_soc);
|
||||
pr_debug("Reported SOC = %d\n", last_soc);
|
||||
chip->t_soc_queried = now;
|
||||
chip->last_reported_soc = last_soc;
|
||||
|
||||
return last_soc;
|
||||
}
|
||||
|
@ -2251,7 +2402,8 @@ static void calib_hkadc(struct pm8921_bms_chip *chip)
|
|||
}
|
||||
voltage = xoadc_reading_to_microvolt(result.adc_code);
|
||||
|
||||
usb_chg = usb_chg_plugged_in();
|
||||
usb_chg = usb_chg_plugged_in(chip);
|
||||
|
||||
pr_debug("result 0.625V = 0x%x, voltage = %duV adc_meas = %lld "
|
||||
"usb_chg = %d\n",
|
||||
result.adc_code, voltage, result.measurement,
|
||||
|
@ -2738,7 +2890,8 @@ static void check_initial_ocv(struct pm8921_bms_chip *chip)
|
|||
*/
|
||||
ocv_uv = 0;
|
||||
pm_bms_read_output_data(chip, LAST_GOOD_OCV_VALUE, &ocv_raw);
|
||||
usb_chg = usb_chg_plugged_in();
|
||||
usb_chg = usb_chg_plugged_in(chip);
|
||||
|
||||
rc = convert_vbatt_raw_to_uv(chip, usb_chg, ocv_raw, &ocv_uv);
|
||||
if (rc || ocv_uv == 0) {
|
||||
rc = adc_based_ocv(chip, &ocv_uv);
|
||||
|
@ -2779,6 +2932,8 @@ static int set_battery_data(struct pm8921_bms_chip *chip)
|
|||
goto desay;
|
||||
else if (chip->batt_type == BATT_PALLADIUM)
|
||||
goto palladium;
|
||||
else if (chip->batt_type == BATT_LGE)
|
||||
goto lge;
|
||||
|
||||
battery_id = read_battery_id(chip);
|
||||
if (battery_id < 0) {
|
||||
|
@ -2817,6 +2972,8 @@ desay:
|
|||
chip->default_rbatt_mohm = desay_5200_data.default_rbatt_mohm;
|
||||
chip->delta_rbatt_mohm = desay_5200_data.delta_rbatt_mohm;
|
||||
return 0;
|
||||
lge:
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum bms_request_operation {
|
||||
|
@ -3197,6 +3354,17 @@ static int __devinit pm8921_bms_probe(struct platform_device *pdev)
|
|||
chip->batt_id_channel = pdata->bms_cdata.batt_id_channel;
|
||||
chip->revision = pm8xxx_get_revision(chip->dev->parent);
|
||||
chip->enable_fcc_learning = pdata->enable_fcc_learning;
|
||||
chip->last_reported_soc = -EINVAL;
|
||||
chip->eoc_check_soc = pdata->eoc_check_soc;
|
||||
chip->soc_adjusted = 0;
|
||||
chip->bms_support_wlc = pdata->bms_support_wlc;
|
||||
if (chip->bms_support_wlc) {
|
||||
chip->wlc_term_ua = pdata->wlc_term_ua;
|
||||
chip->wlc_max_voltage_uv = pdata->wlc_max_voltage_uv;
|
||||
chip->wlc_is_plugged = pdata->wlc_is_plugged;
|
||||
}
|
||||
chip->vbat_at_cv = -EINVAL;
|
||||
chip->first_fixed_iavg_ma = pdata->first_fixed_iavg_ma;
|
||||
|
||||
mutex_init(&chip->calib_mutex);
|
||||
INIT_WORK(&chip->calib_hkadc_work, calibrate_hkadc_work);
|
||||
|
|
|
@ -274,6 +274,7 @@ struct pm8921_chg_chip {
|
|||
struct delayed_work update_heartbeat_work;
|
||||
struct delayed_work eoc_work;
|
||||
struct delayed_work unplug_check_work;
|
||||
struct delayed_work unplug_usbcheck_work;
|
||||
struct delayed_work vin_collapse_check_work;
|
||||
struct wake_lock eoc_wake_lock;
|
||||
enum pm8921_chg_cold_thr cold_thr;
|
||||
|
@ -284,6 +285,10 @@ struct pm8921_chg_chip {
|
|||
bool has_dc_supply;
|
||||
u8 active_path;
|
||||
int recent_reported_soc;
|
||||
unsigned int ext_warm_i_limit;
|
||||
int ext_batt_health;
|
||||
int ext_batt_temp_monitor;
|
||||
int eoc_check_soc;
|
||||
};
|
||||
|
||||
/* user space parameter to limit usb current */
|
||||
|
@ -301,6 +306,10 @@ static struct pm8921_chg_chip *the_chip;
|
|||
|
||||
static struct pm8xxx_adc_arb_btm_param btm_config;
|
||||
|
||||
#ifdef CONFIG_WIRELESS_CHARGER
|
||||
static int wireless_charging;
|
||||
#endif
|
||||
|
||||
static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
|
||||
u8 mask, u8 val)
|
||||
{
|
||||
|
@ -539,6 +548,7 @@ static int pm_chg_vddmax_set(struct pm8921_chg_chip *chip, int voltage)
|
|||
ret |= __pm_chg_vddmax_set(chip, current_mv);
|
||||
}
|
||||
}
|
||||
|
||||
ret |= __pm_chg_vddmax_set(chip, voltage);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1286,16 +1296,36 @@ static int pm_power_set_property_usb(struct power_supply *psy,
|
|||
enum power_supply_property psp,
|
||||
const union power_supply_propval *val)
|
||||
{
|
||||
struct pm8921_chg_chip *chip = the_chip;
|
||||
|
||||
/* Check if called before init */
|
||||
if (!the_chip)
|
||||
if (!chip)
|
||||
return -EINVAL;
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
if (val->intval &&
|
||||
val->intval <= (USB_WALL_THRESHOLD_MA*1000)) {
|
||||
usb_target_ma = 0;
|
||||
} else {
|
||||
usb_target_ma = val->intval/1000;
|
||||
if (!delayed_work_pending(&chip->unplug_check_work)) {
|
||||
schedule_delayed_work(
|
||||
&chip->unplug_check_work,
|
||||
round_jiffies_relative(msecs_to_jiffies
|
||||
(UNPLUG_CHECK_WAIT_PERIOD_MS)));
|
||||
}
|
||||
}
|
||||
pr_info("usb_target_ma %d\n", usb_target_ma);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_PRESENT:
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_SCOPE:
|
||||
if (val->intval == POWER_SUPPLY_SCOPE_SYSTEM)
|
||||
return switch_usb_to_host_mode(the_chip);
|
||||
return switch_usb_to_host_mode(chip);
|
||||
if (val->intval == POWER_SUPPLY_SCOPE_DEVICE)
|
||||
return switch_usb_to_charge_mode(the_chip);
|
||||
return switch_usb_to_charge_mode(chip);
|
||||
else
|
||||
return -EINVAL;
|
||||
break;
|
||||
|
@ -1338,10 +1368,12 @@ static int pm_power_get_property_usb(struct power_supply *psy,
|
|||
return 0;
|
||||
|
||||
/* USB charging */
|
||||
if (usb_target_ma < USB_WALL_THRESHOLD_MA)
|
||||
if (usb_target_ma == 0)
|
||||
val->intval = the_chip->usb_present;
|
||||
else if (usb_target_ma <= USB_WALL_THRESHOLD_MA)
|
||||
val->intval = is_usb_chg_plugged_in(the_chip);
|
||||
else
|
||||
return 0;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case POWER_SUPPLY_PROP_SCOPE:
|
||||
|
@ -1458,15 +1490,19 @@ static int get_prop_batt_health(struct pm8921_chg_chip *chip)
|
|||
{
|
||||
int temp;
|
||||
|
||||
temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
|
||||
if (temp)
|
||||
return POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
if (chip->ext_batt_temp_monitor) {
|
||||
return chip->ext_batt_health;
|
||||
} else {
|
||||
temp = pm_chg_get_rt_status(chip, BATTTEMP_HOT_IRQ);
|
||||
if (temp)
|
||||
return POWER_SUPPLY_HEALTH_OVERHEAT;
|
||||
|
||||
temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
|
||||
if (temp)
|
||||
return POWER_SUPPLY_HEALTH_COLD;
|
||||
temp = pm_chg_get_rt_status(chip, BATTTEMP_COLD_IRQ);
|
||||
if (temp)
|
||||
return POWER_SUPPLY_HEALTH_COLD;
|
||||
|
||||
return POWER_SUPPLY_HEALTH_GOOD;
|
||||
return POWER_SUPPLY_HEALTH_GOOD;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_prop_charge_type(struct pm8921_chg_chip *chip)
|
||||
|
@ -1514,10 +1550,25 @@ static int get_prop_batt_status(struct pm8921_chg_chip *chip)
|
|||
if (!pm_chg_get_rt_status(chip, BATT_INSERTED_IRQ)
|
||||
|| !pm_chg_get_rt_status(chip, BAT_TEMP_OK_IRQ)
|
||||
|| pm_chg_get_rt_status(chip, CHGHOT_IRQ)
|
||||
|| pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
|
||||
|| (!chip->eoc_check_soc &&
|
||||
pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ))
|
||||
|| (chip->ext_batt_temp_monitor &&
|
||||
(chip->ext_batt_health == POWER_SUPPLY_HEALTH_OVERHEAT)))
|
||||
|
||||
batt_state = POWER_SUPPLY_STATUS_NOT_CHARGING;
|
||||
}
|
||||
|
||||
if (chip->eoc_check_soc) {
|
||||
if (get_prop_batt_capacity(chip) == 100) {
|
||||
if (batt_state == POWER_SUPPLY_STATUS_CHARGING)
|
||||
batt_state = POWER_SUPPLY_STATUS_FULL;
|
||||
} else {
|
||||
if (batt_state == POWER_SUPPLY_STATUS_FULL)
|
||||
batt_state = POWER_SUPPLY_STATUS_CHARGING;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("batt_state = %d fsm_state = %d \n",batt_state, fsm_state);
|
||||
return batt_state;
|
||||
}
|
||||
|
||||
|
@ -1551,6 +1602,12 @@ static int pm_batt_power_get_property(struct power_supply *psy,
|
|||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_STATUS:
|
||||
#ifdef CONFIG_WIRELESS_CHARGER
|
||||
if(wireless_charging) {
|
||||
val->intval = 1; //POWER_SUPPLY_STATUS_CHARGING
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
val->intval = get_prop_batt_status(chip);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CHARGE_TYPE:
|
||||
|
@ -1737,6 +1794,32 @@ int pm8921_charger_enable(bool enable)
|
|||
}
|
||||
EXPORT_SYMBOL(pm8921_charger_enable);
|
||||
|
||||
int pm8921_force_start_charging(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!the_chip) {
|
||||
pr_err("called before init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (the_chip->eoc_check_soc) {
|
||||
rc = pm_chg_vbatdet_set(the_chip,
|
||||
the_chip->max_voltage_mv);
|
||||
if (rc) {
|
||||
pr_err("failed to set vbatdet\n");
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = pm_chg_auto_enable(the_chip, 1);
|
||||
if (rc)
|
||||
pr_err("Failed rc=%d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(pm8921_force_start_charging);
|
||||
|
||||
int pm8921_is_usb_chg_plugged_in(void)
|
||||
{
|
||||
if (!the_chip) {
|
||||
|
@ -1814,6 +1897,11 @@ int pm8921_set_max_battery_charge_current(int ma)
|
|||
pr_err("called before init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (thermal_mitigation != 0 && the_chip->thermal_mitigation)
|
||||
ma = min((unsigned int)ma,
|
||||
the_chip->thermal_mitigation[thermal_mitigation]);
|
||||
|
||||
return pm_chg_ibatmax_set(the_chip, ma);
|
||||
}
|
||||
EXPORT_SYMBOL(pm8921_set_max_battery_charge_current);
|
||||
|
@ -1961,13 +2049,82 @@ int pm8921_set_usb_power_supply_type(enum power_supply_type type)
|
|||
if (type < POWER_SUPPLY_TYPE_USB)
|
||||
return -EINVAL;
|
||||
|
||||
the_chip->usb_psy.type = type;
|
||||
power_supply_changed(&the_chip->usb_psy);
|
||||
power_supply_changed(&the_chip->dc_psy);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pm8921_set_usb_power_supply_type);
|
||||
|
||||
#ifdef CONFIG_WIRELESS_CHARGER
|
||||
int set_wireless_power_supply_control(int value)
|
||||
{
|
||||
if (!the_chip) {
|
||||
pr_err("called before init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
wireless_charging = value;
|
||||
power_supply_changed(&the_chip->batt_psy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(set_wireless_power_supply_control);
|
||||
#endif
|
||||
|
||||
int pm8921_set_ext_battery_health(int health, int i_limit)
|
||||
{
|
||||
if (!the_chip) {
|
||||
pr_err("called before init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
the_chip->ext_batt_health = health;
|
||||
the_chip->ext_warm_i_limit = i_limit;
|
||||
|
||||
pr_debug("health = %d i_decrease = %d\n", the_chip->ext_batt_health,
|
||||
the_chip->ext_warm_i_limit);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pm8921_set_ext_battery_health);
|
||||
|
||||
int pm8921_get_batt_state(void)
|
||||
{
|
||||
int batt_state = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
int fsm_state;
|
||||
int i;
|
||||
|
||||
if (!the_chip) {
|
||||
pr_err("called before init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fsm_state = pm_chg_get_fsm_state(the_chip);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(map); i++)
|
||||
if (map[i].fsm_state == fsm_state)
|
||||
batt_state = map[i].batt_state;
|
||||
|
||||
pr_debug("batt_state = %d fsm_state = %d \n",batt_state, fsm_state);
|
||||
return batt_state;
|
||||
}
|
||||
EXPORT_SYMBOL(pm8921_get_batt_state);
|
||||
|
||||
int pm8921_get_batt_health(void)
|
||||
{
|
||||
int batt_health;
|
||||
|
||||
if (!the_chip) {
|
||||
pr_err("called before init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
batt_health = get_prop_batt_health(the_chip);
|
||||
|
||||
pr_debug("batt health = %d\n", batt_health);
|
||||
return batt_health;
|
||||
}
|
||||
EXPORT_SYMBOL(pm8921_get_batt_health);
|
||||
|
||||
int pm8921_batt_temperature(void)
|
||||
{
|
||||
if (!the_chip) {
|
||||
|
@ -2428,11 +2585,15 @@ static irqreturn_t vbatdet_low_irq_handler(int irq, void *data)
|
|||
high_transition = pm_chg_get_rt_status(chip, VBATDET_LOW_IRQ);
|
||||
|
||||
if (high_transition) {
|
||||
/* enable auto charging */
|
||||
pm_chg_auto_enable(chip, !charging_disabled);
|
||||
pr_info("batt fell below resume voltage %s\n",
|
||||
charging_disabled ? "" : "charger enabled");
|
||||
if (!chip->eoc_check_soc
|
||||
|| pm_chg_get_fsm_state(data) == FSM_STATE_ON_BAT_3) {
|
||||
/* enable auto charging */
|
||||
pm_chg_auto_enable(chip, !charging_disabled);
|
||||
pr_info("batt fell below resume voltage %s\n",
|
||||
charging_disabled ? "" : "charger enabled");
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("fsm_state=%d\n", pm_chg_get_fsm_state(data));
|
||||
|
||||
power_supply_changed(&chip->batt_psy);
|
||||
|
@ -2570,29 +2731,43 @@ static void unplug_check_worker(struct work_struct *work)
|
|||
|
||||
rc = pm8xxx_readb(chip->dev->parent, PBL_ACCESS1, &active_path);
|
||||
if (rc) {
|
||||
pr_err("Failed to read PBL_ACCESS1 rc=%d\n", rc);
|
||||
return;
|
||||
pr_warn("Failed to read PBL_ACCESS1 rc=%d\n", rc);
|
||||
//return;
|
||||
}
|
||||
chip->active_path = active_path;
|
||||
|
||||
active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
|
||||
if (the_chip->usb_present) {
|
||||
active_path = USB_ACTIVE_BIT;
|
||||
active_chg_plugged_in = the_chip->usb_present;
|
||||
} else {
|
||||
active_chg_plugged_in = is_active_chg_plugged_in(chip,
|
||||
active_path);
|
||||
}
|
||||
pr_debug("active_path = 0x%x, active_chg_plugged_in = %d\n",
|
||||
active_path, active_chg_plugged_in);
|
||||
if (active_path & USB_ACTIVE_BIT) {
|
||||
pr_debug("USB charger active\n");
|
||||
|
||||
pm_chg_iusbmax_get(chip, &usb_ma);
|
||||
if (usb_ma == 500 && !usb_target_ma) {
|
||||
pr_debug("Stopping Unplug Check Worker USB == 500mA\n");
|
||||
disable_input_voltage_regulation(chip);
|
||||
return;
|
||||
}
|
||||
if (!usb_target_ma) {
|
||||
if (usb_ma > 500) {
|
||||
usb_ma = 500;
|
||||
__pm8921_charger_vbus_draw(usb_ma);
|
||||
pr_info("usb_now=%d, usb_target = %d\n",
|
||||
usb_ma, 500);
|
||||
goto check_again_later;
|
||||
} else if (usb_ma == 500) {
|
||||
pr_info("Stopping Unplug Check Worker"
|
||||
" USB == 500mA\n");
|
||||
disable_input_voltage_regulation(chip);
|
||||
return;
|
||||
}
|
||||
|
||||
if (usb_ma <= 100) {
|
||||
pr_debug(
|
||||
"Unenumerated or suspended usb_ma = %d skip\n",
|
||||
usb_ma);
|
||||
goto check_again_later;
|
||||
if (usb_ma <= 100) {
|
||||
pr_debug(
|
||||
"Unenumerated or suspended usb_ma = %d"
|
||||
" skip\n", usb_ma);
|
||||
goto check_again_later;
|
||||
}
|
||||
}
|
||||
} else if (active_path & DC_ACTIVE_BIT) {
|
||||
pr_debug("DC charger active\n");
|
||||
|
@ -2604,7 +2779,7 @@ static void unplug_check_worker(struct work_struct *work)
|
|||
/* No charger active */
|
||||
if (!(is_usb_chg_plugged_in(chip)
|
||||
&& !(is_dc_chg_plugged_in(chip)))) {
|
||||
pr_debug(
|
||||
pr_info(
|
||||
"Stop: chg removed reg_loop = %d, fsm = %d ibat = %d\n",
|
||||
pm_chg_get_regulation_loop(chip),
|
||||
pm_chg_get_fsm_state(chip),
|
||||
|
@ -2623,7 +2798,7 @@ static void unplug_check_worker(struct work_struct *work)
|
|||
usb_target_ma = usb_ma;
|
||||
/* end AICL here */
|
||||
__pm8921_charger_vbus_draw(usb_ma);
|
||||
pr_debug("usb_now=%d, usb_target = %d\n",
|
||||
pr_info("VIN: usb_now=%d, usb_target = %d\n",
|
||||
usb_ma, usb_target_ma);
|
||||
}
|
||||
}
|
||||
|
@ -2657,8 +2832,13 @@ static void unplug_check_worker(struct work_struct *work)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
active_chg_plugged_in = is_active_chg_plugged_in(chip, active_path);
|
||||
if(the_chip->usb_present) {
|
||||
active_path = USB_ACTIVE_BIT;
|
||||
active_chg_plugged_in =the_chip->usb_present;
|
||||
} else {
|
||||
active_chg_plugged_in = is_active_chg_plugged_in(chip,
|
||||
active_path);
|
||||
}
|
||||
pr_debug("active_path = 0x%x, active_chg = %d\n",
|
||||
active_path, active_chg_plugged_in);
|
||||
chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
|
||||
|
@ -2674,12 +2854,13 @@ static void unplug_check_worker(struct work_struct *work)
|
|||
if (usb_ma < usb_target_ma) {
|
||||
increase_usb_ma_value(&usb_ma);
|
||||
__pm8921_charger_vbus_draw(usb_ma);
|
||||
pr_debug("usb_now=%d, usb_target = %d\n",
|
||||
pr_info("usb_now=%d, usb_target = %d\n",
|
||||
usb_ma, usb_target_ma);
|
||||
} else {
|
||||
usb_target_ma = usb_ma;
|
||||
}
|
||||
}
|
||||
|
||||
check_again_later:
|
||||
/* schedule to check again later */
|
||||
schedule_delayed_work(&chip->unplug_check_work,
|
||||
|
@ -2702,6 +2883,15 @@ static irqreturn_t fastchg_irq_handler(int irq, void *data)
|
|||
{
|
||||
struct pm8921_chg_chip *chip = data;
|
||||
int high_transition;
|
||||
int rc;
|
||||
|
||||
if (chip->eoc_check_soc) {
|
||||
rc = pm_chg_vbatdet_set(chip,
|
||||
chip->max_voltage_mv
|
||||
- chip->resume_voltage_delta);
|
||||
if (rc)
|
||||
pr_err("failed to set vbatdet rc=%d\n", rc);
|
||||
}
|
||||
|
||||
high_transition = pm_chg_get_rt_status(chip, FASTCHG_IRQ);
|
||||
if (high_transition && !delayed_work_pending(&chip->eoc_work)) {
|
||||
|
@ -2710,6 +2900,7 @@ static irqreturn_t fastchg_irq_handler(int irq, void *data)
|
|||
round_jiffies_relative(msecs_to_jiffies
|
||||
(EOC_CHECK_PERIOD_MS)));
|
||||
}
|
||||
|
||||
power_supply_changed(&chip->batt_psy);
|
||||
bms_notify_check(chip);
|
||||
return IRQ_HANDLED;
|
||||
|
@ -2768,6 +2959,28 @@ static irqreturn_t batttemp_cold_irq_handler(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void unplug_usbcheck_work(struct work_struct *work)
|
||||
{
|
||||
int usb_vin;
|
||||
struct pm8xxx_adc_chan_result vchg;
|
||||
struct delayed_work *dwork = to_delayed_work(work);
|
||||
struct pm8921_chg_chip *chip = container_of(dwork,
|
||||
struct pm8921_chg_chip, unplug_usbcheck_work);
|
||||
|
||||
pm8xxx_adc_read(CHANNEL_USBIN, &vchg);
|
||||
usb_vin = vchg.physical;
|
||||
pr_info("usb_vin : %d, max_voltage_mv=%d\n", usb_vin, chip->max_voltage_mv);
|
||||
|
||||
if ((usb_vin/1000 <= chip->max_voltage_mv) &&
|
||||
(usb_vin/1000 > PM8921_CHG_VDDMAX_MIN)){
|
||||
pr_info(" Turn off USB ovp \n");
|
||||
unplug_ovp_fet_open(chip);
|
||||
}
|
||||
power_supply_changed(&chip->batt_psy);
|
||||
power_supply_changed(&chip->usb_psy);
|
||||
power_supply_changed(&chip->dc_psy);
|
||||
}
|
||||
|
||||
static irqreturn_t chg_gone_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct pm8921_chg_chip *chip = data;
|
||||
|
@ -2776,11 +2989,20 @@ static irqreturn_t chg_gone_irq_handler(int irq, void *data)
|
|||
usb_chg_plugged_in = is_usb_chg_plugged_in(chip);
|
||||
chg_gone = pm_chg_get_rt_status(chip, CHG_GONE_IRQ);
|
||||
|
||||
pr_debug("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
|
||||
pr_debug("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
|
||||
pr_info("chg_gone=%d, usb_valid = %d\n", chg_gone, usb_chg_plugged_in);
|
||||
pr_info("Chg gone fsm_state=%d\n", pm_chg_get_fsm_state(data));
|
||||
|
||||
if (chg_gone && usb_chg_plugged_in) {
|
||||
pr_info("schedule to check again here\n");
|
||||
/* schedule to check again later */
|
||||
schedule_delayed_work(&chip->unplug_usbcheck_work,
|
||||
round_jiffies_relative(msecs_to_jiffies
|
||||
(UNPLUG_CHECK_WAIT_PERIOD_MS)));
|
||||
}
|
||||
|
||||
power_supply_changed(&chip->batt_psy);
|
||||
power_supply_changed(&chip->usb_psy);
|
||||
power_supply_changed(&chip->dc_psy);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
/*
|
||||
|
@ -3126,6 +3348,7 @@ static void eoc_worker(struct work_struct *work)
|
|||
struct pm8921_chg_chip, eoc_work);
|
||||
static int count;
|
||||
int end;
|
||||
int percent_soc;
|
||||
|
||||
pm_chg_failed_clear(chip, 1);
|
||||
end = is_charging_finished(chip);
|
||||
|
@ -3154,6 +3377,12 @@ static void eoc_worker(struct work_struct *work)
|
|||
count = 0;
|
||||
}
|
||||
|
||||
if (chip->eoc_check_soc) {
|
||||
percent_soc = get_prop_batt_capacity(chip);
|
||||
if (percent_soc == 100)
|
||||
count = CONSECUTIVE_COUNT;
|
||||
}
|
||||
|
||||
if (count == CONSECUTIVE_COUNT) {
|
||||
count = 0;
|
||||
pr_info("End of Charging\n");
|
||||
|
@ -3200,6 +3429,9 @@ static void set_appropriate_battery_current(struct pm8921_chg_chip *chip)
|
|||
if (chip->is_bat_warm)
|
||||
chg_current = min(chg_current, chip->warm_bat_chg_current);
|
||||
|
||||
if (chip->ext_warm_i_limit && chip->ext_batt_temp_monitor)
|
||||
chg_current = min(chg_current, chip->ext_warm_i_limit);
|
||||
|
||||
if (thermal_mitigation != 0 && chip->thermal_mitigation)
|
||||
chg_current = min(chg_current,
|
||||
chip->thermal_mitigation[thermal_mitigation]);
|
||||
|
@ -3424,14 +3656,14 @@ static void __devinit determine_initial_state(struct pm8921_chg_chip *chip)
|
|||
pm8921_chg_enable_irq(chip, USBIN_VALID_IRQ);
|
||||
pm8921_chg_enable_irq(chip, BATT_REMOVED_IRQ);
|
||||
pm8921_chg_enable_irq(chip, BATT_INSERTED_IRQ);
|
||||
pm8921_chg_enable_irq(chip, USBIN_OV_IRQ);
|
||||
pm8921_chg_enable_irq(chip, USBIN_UV_IRQ);
|
||||
pm8921_chg_enable_irq(chip, DCIN_OV_IRQ);
|
||||
pm8921_chg_enable_irq(chip, DCIN_UV_IRQ);
|
||||
pm8921_chg_enable_irq(chip, CHGFAIL_IRQ);
|
||||
pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
|
||||
pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
|
||||
pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
|
||||
|
||||
if (!chip->ext_batt_temp_monitor)
|
||||
pm8921_chg_enable_irq(chip, BAT_TEMP_OK_IRQ);
|
||||
|
||||
spin_lock_irqsave(&vbus_lock, flags);
|
||||
if (usb_chg_current) {
|
||||
|
@ -4067,6 +4299,105 @@ static void create_debugfs_entries(struct pm8921_chg_chip *chip)
|
|||
}
|
||||
}
|
||||
|
||||
int pm8921_stop_chg_disable_irq(void)
|
||||
{
|
||||
|
||||
struct pm8921_chg_chip *chip = the_chip;
|
||||
|
||||
pm8921_chg_disable_irq(chip, ATCFAIL_IRQ);
|
||||
pm8921_chg_disable_irq(chip, CHGHOT_IRQ);
|
||||
pm8921_chg_disable_irq(chip, ATCDONE_IRQ);
|
||||
pm8921_chg_disable_irq(chip, FASTCHG_IRQ);
|
||||
pm8921_chg_disable_irq(chip, CHGDONE_IRQ);
|
||||
pm8921_chg_disable_irq(chip, VBATDET_IRQ);
|
||||
pm8921_chg_disable_irq(chip, VBATDET_LOW_IRQ);
|
||||
|
||||
return 1;
|
||||
}
|
||||
int pm8921_start_chg_enable_irq(void)
|
||||
{
|
||||
|
||||
struct pm8921_chg_chip *chip = the_chip;
|
||||
|
||||
pm8921_chg_enable_irq(chip, ATCFAIL_IRQ);
|
||||
pm8921_chg_enable_irq(chip, CHGHOT_IRQ);
|
||||
pm8921_chg_enable_irq(chip, ATCDONE_IRQ);
|
||||
pm8921_chg_enable_irq(chip, FASTCHG_IRQ);
|
||||
pm8921_chg_enable_irq(chip, CHGDONE_IRQ);
|
||||
pm8921_chg_enable_irq(chip, VBATDET_IRQ);
|
||||
pm8921_chg_enable_irq(chip, VBATDET_LOW_IRQ);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ssize_t pm8921_chg_status_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int fsm_state, is_charging, r;
|
||||
bool b_chg_ok = false;
|
||||
|
||||
if (!the_chip) {
|
||||
pr_err("called before init\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fsm_state = pm_chg_get_fsm_state(the_chip);
|
||||
is_charging = is_battery_charging(fsm_state);
|
||||
|
||||
if (is_charging) {
|
||||
b_chg_ok = true;
|
||||
r = sprintf(buf, "%d\n", b_chg_ok);
|
||||
pr_info("pm8921_chg_status_show , true ! buf = %s, is_charging = %d\n",
|
||||
buf, is_charging);
|
||||
} else {
|
||||
b_chg_ok = false;
|
||||
r = sprintf(buf, "%d\n", b_chg_ok);
|
||||
pr_info("pm8921_chg_status_show , false ! buf = %s, is_charging = %d\n",
|
||||
buf, is_charging);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static ssize_t pm8921_chg_status_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ret = 0, batt_status = 0;
|
||||
struct pm8921_chg_chip *chip = the_chip;
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
||||
batt_status = get_prop_batt_status(chip);
|
||||
|
||||
if (strncmp(buf, "0", 1) == 0) {
|
||||
/* stop charging */
|
||||
pr_info("pm8921_chg_status_store : stop charging start\n");
|
||||
if (batt_status == POWER_SUPPLY_STATUS_CHARGING) {
|
||||
ret = pm8921_stop_chg_disable_irq();
|
||||
pm_chg_auto_enable(chip, 0);
|
||||
pm_chg_charge_dis(chip,1);
|
||||
pr_info("pm8921_chg_status_store : stop charging end\n");
|
||||
}
|
||||
} else if (strncmp(buf, "1", 1) == 0) {
|
||||
/* start charging */
|
||||
pr_info("pm8921_chg_status_store : start charging start\n");
|
||||
if (batt_status != POWER_SUPPLY_STATUS_CHARGING) {
|
||||
ret = pm8921_start_chg_enable_irq();
|
||||
pm_chg_auto_enable(chip, 1);
|
||||
pm_chg_charge_dis(chip,0);
|
||||
pr_info("pm8921_chg_status_store : start charging end\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(ret == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
DEVICE_ATTR(charge, 0664, pm8921_chg_status_show, pm8921_chg_status_store);
|
||||
|
||||
static int pm8921_charger_suspend_noirq(struct device *dev)
|
||||
{
|
||||
int rc;
|
||||
|
@ -4199,7 +4530,11 @@ static int __devinit pm8921_charger_probe(struct platform_device *pdev)
|
|||
chip->hot_thr = pdata->hot_thr;
|
||||
chip->rconn_mohm = pdata->rconn_mohm;
|
||||
chip->led_src_config = pdata->led_src_config;
|
||||
chip->has_dc_supply = pdata->has_dc_supply;
|
||||
chip->has_dc_supply = pdata->has_dc_supply;
|
||||
chip->ext_batt_temp_monitor = pdata->ext_batt_temp_monitor;
|
||||
chip->eoc_check_soc = pdata->eoc_check_soc;
|
||||
if (chip->ext_batt_temp_monitor)
|
||||
chip->ext_batt_health = POWER_SUPPLY_HEALTH_GOOD;
|
||||
|
||||
rc = pm8921_chg_hw_init(chip);
|
||||
if (rc) {
|
||||
|
@ -4256,6 +4591,7 @@ static int __devinit pm8921_charger_probe(struct platform_device *pdev)
|
|||
INIT_DELAYED_WORK(&chip->vin_collapse_check_work,
|
||||
vin_collapse_check_worker);
|
||||
INIT_DELAYED_WORK(&chip->unplug_check_work, unplug_check_worker);
|
||||
INIT_DELAYED_WORK(&chip->unplug_usbcheck_work, unplug_usbcheck_work);
|
||||
|
||||
rc = request_irqs(chip, pdev);
|
||||
if (rc) {
|
||||
|
@ -4266,7 +4602,8 @@ static int __devinit pm8921_charger_probe(struct platform_device *pdev)
|
|||
enable_irq_wake(chip->pmic_chg_irq[USBIN_VALID_IRQ]);
|
||||
enable_irq_wake(chip->pmic_chg_irq[USBIN_OV_IRQ]);
|
||||
enable_irq_wake(chip->pmic_chg_irq[USBIN_UV_IRQ]);
|
||||
enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
|
||||
if (!chip->ext_batt_temp_monitor)
|
||||
enable_irq_wake(chip->pmic_chg_irq[BAT_TEMP_OK_IRQ]);
|
||||
enable_irq_wake(chip->pmic_chg_irq[VBATDET_LOW_IRQ]);
|
||||
enable_irq_wake(chip->pmic_chg_irq[FASTCHG_IRQ]);
|
||||
/*
|
||||
|
@ -4300,6 +4637,12 @@ static int __devinit pm8921_charger_probe(struct platform_device *pdev)
|
|||
/* determine what state the charger is in */
|
||||
determine_initial_state(chip);
|
||||
|
||||
rc = device_create_file(&pdev->dev, &dev_attr_charge);
|
||||
if (rc) {
|
||||
pr_err("Couldn't device_create_file charge! rc=%d\n",rc);
|
||||
goto free_irq;
|
||||
}
|
||||
|
||||
if (chip->update_time) {
|
||||
INIT_DELAYED_WORK(&chip->update_heartbeat_work,
|
||||
update_heartbeat);
|
||||
|
@ -4326,6 +4669,7 @@ static int __devexit pm8921_charger_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct pm8921_chg_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
device_remove_file(&pdev->dev, &dev_attr_charge);
|
||||
free_irqs(chip);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
the_chip = NULL;
|
||||
|
|
|
@ -45,7 +45,10 @@ static ssize_t power_supply_show_property(struct device *dev,
|
|||
char *buf) {
|
||||
static char *type_text[] = {
|
||||
"Unknown", "Battery", "UPS", "Mains", "USB",
|
||||
"USB_DCP", "USB_CDP", "USB_ACA"
|
||||
"USB_DCP", "USB_CDP", "USB_ACA",
|
||||
#ifdef CONFIG_WIRELESS_CHARGER
|
||||
"Wireless"
|
||||
#endif
|
||||
};
|
||||
static char *status_text[] = {
|
||||
"Unknown", "Charging", "Discharging", "Not charging", "Full"
|
||||
|
|
|
@ -1114,6 +1114,8 @@ static int msm_otg_notify_power_supply(struct msm_otg *motg, unsigned mA)
|
|||
return 0;
|
||||
}
|
||||
/* Set max current limit */
|
||||
dev_info(motg->phy.dev, "current: %d -> %d (mA)\n",
|
||||
motg->cur_power, mA);
|
||||
if (power_supply_set_current_limit(psy, 1000*mA))
|
||||
goto psy_not_supported;
|
||||
|
||||
|
@ -1148,12 +1150,8 @@ static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
|
|||
|
||||
dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
|
||||
|
||||
/*
|
||||
* Use Power Supply API if supported, otherwise fallback
|
||||
* to legacy pm8921 API.
|
||||
*/
|
||||
if (msm_otg_notify_power_supply(motg, mA))
|
||||
pm8921_charger_vbus_draw(mA);
|
||||
pm8921_charger_vbus_draw(mA);
|
||||
msm_otg_notify_power_supply(motg, mA);
|
||||
|
||||
motg->cur_power = mA;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,27 @@ enum pm8xxx_version {
|
|||
#define PM8XXX_REVISION_8917_TEST 0
|
||||
#define PM8XXX_REVISION_8917_1p0 1
|
||||
|
||||
#define PM8XXX_RESTART_UNKNOWN 0
|
||||
#define PM8XXX_RESTART_CBL 1
|
||||
#define PM8XXX_RESTART_KPD 2
|
||||
#define PM8XXX_RESTART_CHG 3
|
||||
#define PM8XXX_RESTART_SMPL 4
|
||||
#define PM8XXX_RESTART_RTC 5
|
||||
#define PM8XXX_RESTART_HARD_RESET 6
|
||||
#define PM8XXX_RESTART_GEN_PURPOSE 7
|
||||
#define PM8XXX_RESTART_REASON_MASK 0x07
|
||||
|
||||
static const char * const pm8xxx_restart_reason_str[] = {
|
||||
[0] = "Unknown",
|
||||
[1] = "Triggered from CBL (external charger)",
|
||||
[2] = "Triggered from KPD (power key press)",
|
||||
[3] = "Triggered from CHG (usb charger insertion)",
|
||||
[4] = "Triggered from SMPL (sudden momentary power loss)",
|
||||
[5] = "Triggered from RTC (real time clock)",
|
||||
[6] = "Triggered by Hard Reset",
|
||||
[7] = "Triggered by General Purpose Trigger",
|
||||
};
|
||||
|
||||
struct pm8xxx_drvdata {
|
||||
int (*pmic_readb) (const struct device *dev,
|
||||
u16 addr, u8 *val);
|
||||
|
@ -88,6 +109,8 @@ struct pm8xxx_drvdata {
|
|||
int irq);
|
||||
enum pm8xxx_version (*pmic_get_version) (const struct device *dev);
|
||||
int (*pmic_get_revision) (const struct device *dev);
|
||||
u8 (*pmic_restart_reason)
|
||||
(const struct device *dev);
|
||||
void *pm_chip_data;
|
||||
};
|
||||
|
||||
|
@ -156,4 +179,12 @@ static inline int pm8xxx_get_revision(const struct device *dev)
|
|||
return dd->pmic_get_revision(dev);
|
||||
}
|
||||
|
||||
static inline u8 pm8xxx_restart_reason(const struct device *dev)
|
||||
{
|
||||
struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
|
||||
|
||||
if (!dd)
|
||||
return -EINVAL;
|
||||
return dd->pmic_restart_reason(dev);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -108,6 +108,7 @@ enum battery_type {
|
|||
BATT_UNKNOWN = 0,
|
||||
BATT_PALLADIUM,
|
||||
BATT_DESAY,
|
||||
BATT_LGE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -134,11 +135,18 @@ struct pm8921_bms_platform_data {
|
|||
int ignore_shutdown_soc;
|
||||
int adjust_soc_low_threshold;
|
||||
int chg_term_ua;
|
||||
int eoc_check_soc;
|
||||
int bms_support_wlc;
|
||||
int wlc_term_ua;
|
||||
int wlc_max_voltage_uv;
|
||||
int (*wlc_is_plugged)(void);
|
||||
int first_fixed_iavg_ma;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)
|
||||
extern struct pm8921_bms_battery_data palladium_1500_data;
|
||||
extern struct pm8921_bms_battery_data desay_5200_data;
|
||||
extern struct pm8921_bms_battery_data lge_2100_mako_data;
|
||||
/**
|
||||
* pm8921_bms_get_vsense_avg - return the voltage across the sense
|
||||
* resitor in microvolts
|
||||
|
|
|
@ -138,6 +138,7 @@ struct pm8921_charger_platform_data {
|
|||
unsigned int max_bat_chg_current;
|
||||
unsigned int cool_bat_chg_current;
|
||||
unsigned int warm_bat_chg_current;
|
||||
int ext_batt_temp_monitor;
|
||||
unsigned int cool_bat_voltage;
|
||||
unsigned int warm_bat_voltage;
|
||||
unsigned int (*get_batt_capacity_percent) (void);
|
||||
|
@ -157,6 +158,7 @@ struct pm8921_charger_platform_data {
|
|||
enum pm8921_chg_hot_thr hot_thr;
|
||||
int rconn_mohm;
|
||||
enum pm8921_chg_led_src_config led_src_config;
|
||||
int eoc_check_soc;
|
||||
};
|
||||
|
||||
enum pm8921_charger_source {
|
||||
|
@ -285,6 +287,11 @@ int pm8921_usb_ovp_set_hystersis(enum pm8921_usb_debounce_time ms);
|
|||
*
|
||||
*/
|
||||
int pm8921_usb_ovp_disable(int disable);
|
||||
|
||||
int pm8921_get_batt_state(void);
|
||||
int pm8921_force_start_charging(void);
|
||||
int pm8921_get_batt_health(void);
|
||||
|
||||
/**
|
||||
* pm8921_is_batfet_closed - battery fet status
|
||||
*
|
||||
|
|
44
include/linux/platform_data/battery_temp_ctrl.h
Normal file
44
include/linux/platform_data/battery_temp_ctrl.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright(c) 2012, LG Electronics Inc. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BATTERY_TEMP_CTRL_H
|
||||
#define __BATTERY_TEMP_CTRL_H
|
||||
|
||||
struct batt_temp_pdata {
|
||||
int (*set_chg_i_limit)(int max_current);
|
||||
int (*get_chg_i_limit)(void);
|
||||
int (*set_health_state)(int state, int i_value);
|
||||
int (*enable_charging)(void);
|
||||
int (*disable_charging)(void);
|
||||
int (*is_ext_power)(void);
|
||||
int update_time;
|
||||
int *temp_level;
|
||||
int temp_nums;
|
||||
int thr_mvolt;
|
||||
int i_decrease;
|
||||
int i_restore;
|
||||
};
|
||||
|
||||
enum {
|
||||
TEMP_LEVEL_POWER_OFF = 0,
|
||||
TEMP_LEVEL_WARNINGOVERHEAT,
|
||||
TEMP_LEVEL_HOT_STOPCHARGING,
|
||||
TEMP_LEVEL_DECREASING,
|
||||
TEMP_LEVEL_HOT_RECHARGING,
|
||||
TEMP_LEVEL_COLD_RECHARGING,
|
||||
TEMP_LEVEL_WARNING_COLD,
|
||||
TEMP_LEVEL_COLD_STOPCHARGING,
|
||||
TEMP_LEVEL_NORMAL
|
||||
};
|
||||
#endif
|
34
include/linux/power/bq51051b_charger.h
Normal file
34
include/linux/power/bq51051b_charger.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2012, Kyungtae Oh <kyungtae.oh@lge.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_POWER_BQ51051B_CHARGER_H__
|
||||
#define __LINUX_POWER_BQ51051B_CHARGER_H__
|
||||
|
||||
#define BQ51051B_WLC_DEV_NAME "bq51051b_wlc"
|
||||
|
||||
#define WLC_DEG
|
||||
|
||||
#ifdef WLC_DEG
|
||||
#define WLC_DBG_INFO(fmt, args...) \
|
||||
pr_info("wlc: %s: " fmt, __func__, ##args)
|
||||
#define WLC_DBG(fmt, args...) \
|
||||
pr_debug("wlc: %s: " fmt, __func__, ##args)
|
||||
#else
|
||||
#define WLC_DBG_INFO(fmt, args...) do { } while(0)
|
||||
#define WLC_DBG(fmt, arges...) do { } while(0)
|
||||
#endif
|
||||
|
||||
struct bq51051b_wlc_platform_data {
|
||||
unsigned int chg_state_gpio;
|
||||
unsigned int active_n_gpio;
|
||||
unsigned int wireless_charging;
|
||||
int (*wlc_is_plugged)(void);
|
||||
};
|
||||
#endif
|
|
@ -140,6 +140,9 @@ enum power_supply_type {
|
|||
POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */
|
||||
POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */
|
||||
POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */
|
||||
#ifdef CONFIG_WIRELESS_CHARGER
|
||||
POWER_SUPPLY_TYPE_WIRELESS,
|
||||
#endif
|
||||
};
|
||||
|
||||
union power_supply_propval {
|
||||
|
|
Loading…
Reference in a new issue