power: pm8921-charger: implement thermal mitigation

Implement thermal mitigation in the charger driver. The userspace
daemon can get the battery temperature from
/sys/class/power_supply/battery/temp

and set the mitigation levels on
/sys/module/pm8921_charger/parameters/thermal_mitigation

The battery driver supports 4 levels [0 through 3]. O being normal
and 3 being extreme thermal mitigation.

Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index acd7974..98eb5b5 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -3339,6 +3339,13 @@
 	.keymap_data            = &keymap_data_sim,
 };
 
+static int pm8921_therm_mitigation[] = {
+	1100,
+	700,
+	600,
+	325,
+};
+
 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = {
 	.safety_time		= 180,
 	.update_time		= 1,
@@ -3349,11 +3356,13 @@
 	.cool_temp		= 10,
 	.warm_temp		= 40,
 	.temp_check_period	= 1,
-	.max_bat_chg_current	= 400,
+	.max_bat_chg_current	= 1100,
 	.cool_bat_chg_current	= 350,
 	.warm_bat_chg_current	= 350,
 	.cool_bat_voltage	= 4100,
 	.warm_bat_voltage	= 4100,
+	.thermal_mitigation	= pm8921_therm_mitigation,
+	.thermal_levels		= ARRAY_SIZE(pm8921_therm_mitigation),
 };
 
 static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = {
diff --git a/drivers/power/pm8921-charger.c b/drivers/power/pm8921-charger.c
index 867795b..1b76401 100644
--- a/drivers/power/pm8921-charger.c
+++ b/drivers/power/pm8921-charger.c
@@ -198,9 +198,12 @@
 	int			trkl_current;
 	int			weak_current;
 	int			vin_min;
+	int			*thermal_mitigation;
+	int			thermal_levels;
 };
 
 static int charging_disabled;
+static int thermal_mitigation;
 
 static struct pm8921_chg_chip *the_chip;
 
@@ -1490,6 +1493,47 @@
 module_param_call(disabled, set_disable_status_param, param_get_uint,
 					&charging_disabled, 0644);
 
+/**
+ * set_thermal_mitigation_level -
+ *
+ * Internal function to control battery charging current to reduce
+ * temperature
+ */
+static int set_therm_mitigation_level(const char *val, struct kernel_param *kp)
+{
+	int ret;
+	struct pm8921_chg_chip *chip = the_chip;
+
+	ret = param_set_int(val, kp);
+	if (ret) {
+		pr_err("error setting value %d\n", ret);
+		return ret;
+	}
+
+	if (!chip) {
+		pr_err("called before init\n");
+		return -EINVAL;
+	}
+
+	if (!chip->thermal_mitigation) {
+		pr_err("no thermal mitigation\n");
+		return -EINVAL;
+	}
+
+	if (thermal_mitigation < 0
+		|| thermal_mitigation >= chip->thermal_levels) {
+		pr_err("out of bound level selected\n");
+		return -EINVAL;
+	}
+
+	ret = pm_chg_ibatmax_set(chip,
+			chip->thermal_mitigation[thermal_mitigation]);
+	return ret;
+}
+module_param_call(thermal_mitigation, set_therm_mitigation_level,
+					param_get_uint,
+					&thermal_mitigation, 0644);
+
 static void free_irqs(struct pm8921_chg_chip *chip)
 {
 	int i;
@@ -1995,6 +2039,8 @@
 	chip->trkl_current = pdata->trkl_current;
 	chip->weak_current = pdata->weak_current;
 	chip->vin_min = pdata->vin_min;
+	chip->thermal_mitigation = pdata->thermal_mitigation;
+	chip->thermal_levels = pdata->thermal_levels;
 
 	rc = pm8921_chg_hw_init(chip);
 	if (rc) {
diff --git a/include/linux/mfd/pm8xxx/pm8921-charger.h b/include/linux/mfd/pm8xxx/pm8921-charger.h
index fa891d8..4b74f85 100644
--- a/include/linux/mfd/pm8xxx/pm8921-charger.h
+++ b/include/linux/mfd/pm8xxx/pm8921-charger.h
@@ -60,6 +60,9 @@
  * @vin_min:		the input voltage regulation point (mV) - if the
  *			voltage falls below this, the charger reduces charge
  *			current or stop charging temporarily
+ * @thermal_mitigation: the array of charge currents to use as temperature
+ *			increases
+ * @thermal_levels:	the number of thermal mitigation levels supported
  *
  */
 struct pm8921_charger_platform_data {
@@ -87,6 +90,8 @@
 	int				trkl_current;
 	int				weak_current;
 	int				vin_min;
+	int				*thermal_mitigation;
+	int				thermal_levels;
 };
 
 enum pm8921_charger_source {