power: pm8921-charger: implement temperature control
pm8921 has a special hardware to monitor the battery temperature. Use
this block to program the cool and warm thresholds and reduce charging
current accordingly.
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 0677bcc..b6f88b7 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -165,12 +165,20 @@
unsigned int usb_present;
unsigned int dc_present;
unsigned int usb_charger_current;
+ unsigned int max_bat_chg_current;
unsigned int pmic_chg_irq[PM_CHG_MAX_INTS];
unsigned int safety_time;
unsigned int ttrkl_time;
unsigned int update_time;
unsigned int max_voltage;
unsigned int min_voltage;
+ unsigned int cool_temp;
+ unsigned int warm_temp;
+ unsigned int temp_check_period;
+ unsigned int cool_bat_chg_current;
+ unsigned int warm_bat_chg_current;
+ unsigned int cool_bat_voltage;
+ unsigned int warm_bat_voltage;
unsigned int resume_voltage;
unsigned int term_current;
unsigned int vbat_channel;
@@ -191,6 +199,8 @@
static struct pm8921_chg_chip *the_chip;
+static struct pm8921_adc_arb_btm_param btm_config;
+
static int pm_chg_masked_write(struct pm8921_chg_chip *chip, u16 addr,
u8 mask, u8 val)
{
@@ -1272,6 +1282,69 @@
return IRQ_HANDLED;
}
+static void btm_configure_work(struct work_struct *work)
+{
+ int rc;
+
+ rc = pm8921_adc_btm_configure(&btm_config);
+ if (rc)
+ pr_err("failed to configure btm rc=%d", rc);
+}
+
+DECLARE_WORK(btm_config_work, btm_configure_work);
+
+#define TEMP_HYSTERISIS_DEGC 2
+static void battery_cool(bool enter)
+{
+ pr_debug("enter = %d\n", enter);
+ if (enter) {
+ btm_config.low_thr_temp =
+ the_chip->cool_temp + TEMP_HYSTERISIS_DEGC;
+ pm_chg_ibatmax_set(the_chip, the_chip->cool_bat_chg_current);
+ pm_chg_vddmax_set(the_chip, the_chip->cool_bat_voltage);
+ } else {
+ btm_config.low_thr_temp = the_chip->cool_temp;
+ pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
+ pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+ }
+ schedule_work(&btm_config_work);
+}
+
+static void battery_warm(bool enter)
+{
+ pr_debug("enter = %d\n", enter);
+ if (enter) {
+ btm_config.high_thr_temp =
+ the_chip->warm_temp - TEMP_HYSTERISIS_DEGC;
+ pm_chg_ibatmax_set(the_chip, the_chip->warm_bat_chg_current);
+ pm_chg_vddmax_set(the_chip, the_chip->warm_bat_voltage);
+ } else {
+ btm_config.high_thr_temp = the_chip->warm_temp;
+ pm_chg_ibatmax_set(the_chip, the_chip->max_bat_chg_current);
+ pm_chg_vddmax_set(the_chip, the_chip->max_voltage);
+ }
+ schedule_work(&btm_config_work);
+}
+
+static int configure_btm(struct pm8921_chg_chip *chip)
+{
+ int rc;
+
+ btm_config.btm_warm_fn = battery_warm;
+ btm_config.btm_cool_fn = battery_cool;
+ btm_config.low_thr_temp = chip->cool_temp;
+ btm_config.high_thr_temp = chip->warm_temp;
+ btm_config.interval = chip->temp_check_period;
+ rc = pm8921_adc_btm_configure(&btm_config);
+ if (rc)
+ pr_err("failed to configure btm rc = %d\n", rc);
+ rc = pm8921_adc_btm_start();
+ if (rc)
+ pr_err("failed to start btm rc = %d\n", rc);
+
+ return rc;
+}
+
/**
* set_disable_status_param -
*
@@ -1490,7 +1563,7 @@
}
/* TODO needs to be changed as per the temeperature of the battery */
- rc = pm_chg_ibatmax_set(chip, 400);
+ rc = pm_chg_ibatmax_set(chip, chip->max_bat_chg_current);
if (rc) {
pr_err("Failed to set max current to 400 rc=%d\n", rc);
return rc;
@@ -1748,6 +1821,14 @@
chip->batt_id_channel = pdata->charger_cdata.batt_id_channel;
chip->batt_id_min = pdata->batt_id_min;
chip->batt_id_max = pdata->batt_id_max;
+ chip->cool_temp = pdata->cool_temp;
+ chip->warm_temp = pdata->warm_temp;
+ chip->temp_check_period = pdata->temp_check_period;
+ chip->max_bat_chg_current = pdata->max_bat_chg_current;
+ chip->cool_bat_chg_current = pdata->cool_bat_chg_current;
+ chip->warm_bat_chg_current = pdata->warm_bat_chg_current;
+ chip->cool_bat_voltage = pdata->cool_bat_voltage;
+ chip->warm_bat_voltage = pdata->warm_bat_voltage;
rc = pm8921_chg_hw_init(chip);
if (rc) {
@@ -1780,7 +1861,7 @@
rc = power_supply_register(chip->dev, &chip->usb_psy);
if (rc < 0) {
pr_err("power_supply_register usb failed rc = %d\n", rc);
- goto free_irq;
+ goto free_chip;
}
rc = power_supply_register(chip->dev, &chip->dc_psy);
@@ -1804,6 +1885,17 @@
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]);
+ /*
+ * if both the cool_temp and warm_temp are zero the device doesnt
+ * care for jeita compliance
+ */
+ if (!(chip->cool_temp == 0 && chip->warm_temp == 0)) {
+ rc = configure_btm(chip);
+ if (rc) {
+ pr_err("couldn't register with btm rc=%d\n", rc);
+ goto free_irq;
+ }
+ }
platform_set_drvdata(pdev, chip);
the_chip = chip;