Merge "power: power supply framework : add warm and cool properties"
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index 13b4ba3..f9c759f 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -393,6 +393,13 @@
 	return requeued ? -1 : 0;
 }
 
+static void plist_move(struct plist_head *old, struct plist_head *new)
+{
+	plist_head_init(new);
+	list_splice_tail(&old->node_list, &new->node_list);
+	plist_head_init(old);
+}
+
 /**
  * _adreno_dispatcher_issuecmds() - Issue commmands from pending contexts
  * @adreno_dev: Pointer to the adreno device struct
@@ -403,31 +410,36 @@
 static int _adreno_dispatcher_issuecmds(struct adreno_device *adreno_dev)
 {
 	struct adreno_dispatcher *dispatcher = &adreno_dev->dispatcher;
-	int last_id = 0;
+	struct plist_head tmp;
+	struct adreno_context *drawctxt, *next;
 
+	/* Leave early if the dispatcher isn't in a happy state */
+	if ((dispatcher->state != ADRENO_DISPATCHER_ACTIVE) ||
+		adreno_gpu_fault(adreno_dev) != 0)
+			return 0;
+
+	/* Copy the current context list to a temporary list */
+	spin_lock(&dispatcher->plist_lock);
+	plist_move(&dispatcher->pending, &tmp);
+	spin_unlock(&dispatcher->plist_lock);
+
+	/* Try to fill the ringbuffer as much as possible */
 	while (dispatcher->inflight < _dispatcher_inflight) {
-		struct adreno_context *drawctxt = NULL;
 
-		/* Don't do anything if the dispatcher is paused */
-		if (dispatcher->state != ADRENO_DISPATCHER_ACTIVE)
+		/* Stop doing things if the dispatcher is paused or faulted */
+		if ((dispatcher->state != ADRENO_DISPATCHER_ACTIVE) ||
+			adreno_gpu_fault(adreno_dev) != 0)
 			break;
 
-		if (adreno_gpu_fault(adreno_dev) != 0)
+		if (plist_head_empty(&tmp))
 			break;
 
-		spin_lock(&dispatcher->plist_lock);
+		/* Get the next entry on the list */
+		drawctxt = plist_first_entry(&tmp, struct adreno_context,
+			pending);
 
-		if (!plist_head_empty(&dispatcher->pending)) {
-			drawctxt = plist_first_entry(&dispatcher->pending,
-				struct adreno_context, pending);
-
-			plist_del(&drawctxt->pending, &dispatcher->pending);
-		}
-
-		spin_unlock(&dispatcher->plist_lock);
-
-		if (drawctxt == NULL)
-			break;
+		/* Remove it from the list */
+		plist_del(&drawctxt->pending, &tmp);
 
 		if (kgsl_context_detached(&drawctxt->base) ||
 			drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) {
@@ -435,25 +447,26 @@
 			continue;
 		}
 
-		/*
-		 * Don't loop endlessly on the same stalled context - if we see
-		 * the same context twice in a row then assume that there is
-		 * nothing else to do and bail.  But don't forget to put the
-		 * stalled context back on the queue otherwise it will get
-		 * forgotten
-		 */
-
-		if (last_id == drawctxt->base.id) {
-			dispatcher_queue_context(adreno_dev, drawctxt);
-			kgsl_context_put(&drawctxt->base);
-			break;
-		}
-
-		last_id = drawctxt->base.id;
 		dispatcher_context_sendcmds(adreno_dev, drawctxt);
 		kgsl_context_put(&drawctxt->base);
 	}
 
+	/* Requeue any remaining contexts for the next go around */
+
+	spin_lock(&dispatcher->plist_lock);
+
+	plist_for_each_entry_safe(drawctxt, next, &tmp, pending) {
+		int prio = drawctxt->pending.prio;
+
+		/* Reset the context node */
+		plist_node_init(&drawctxt->pending, prio);
+
+		/* And put it back in the master list */
+		plist_add(&drawctxt->pending, &dispatcher->pending);
+	}
+
+	spin_unlock(&dispatcher->plist_lock);
+
 	return 0;
 }
 
diff --git a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
index 2f6e6a7..14dffa8 100644
--- a/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
+++ b/drivers/media/platform/msm/camera_v2/ispif/msm_ispif.c
@@ -86,11 +86,6 @@
 	long timeout = 0;
 	struct clk *reset_clk[ARRAY_SIZE(ispif_8974_reset_clk_info)];
 
-	if (ispif->csid_version < CSID_VERSION_V30) {
-		/* currently reset is done only for 8974 */
-		return 0;
-	}
-
 	rc = msm_cam_clk_enable(&ispif->pdev->dev,
 		ispif_8974_reset_clk_info, reset_clk,
 		ARRAY_SIZE(ispif_8974_reset_clk_info), 1);
@@ -802,7 +797,7 @@
 
 		ispif_process_irq(ispif, out, VFE0);
 	}
-	if (ispif->vfe_info.num_vfe > 1) {
+	if (ispif->hw_num_isps > 1) {
 		if (out[VFE1].ispifIrqStatus0 & RESET_DONE_IRQ)
 			complete(&ispif->reset_complete[VFE1]);
 
@@ -896,7 +891,13 @@
 		pr_err("%s: ahb_clk enable failed", __func__);
 		goto error_ahb;
 	}
-	msm_ispif_reset_hw(ispif);
+
+	if (of_device_is_compatible(ispif->pdev->dev.of_node,
+				    "qcom,ispif-v3.0")) {
+		/* currently HW reset is implemented for 8974 only */
+		msm_ispif_reset_hw(ispif);
+	}
+
 	rc = msm_ispif_reset(ispif);
 	if (rc == 0) {
 		ispif->ispif_state = ISPIF_POWER_UP;
diff --git a/drivers/power/qpnp-charger.c b/drivers/power/qpnp-charger.c
index 7f77b75..7ccd49d 100644
--- a/drivers/power/qpnp-charger.c
+++ b/drivers/power/qpnp-charger.c
@@ -338,6 +338,7 @@
 	struct qpnp_chg_regulator	boost_vreg;
 	struct qpnp_vadc_chip		*vadc_dev;
 	struct qpnp_adc_tm_chip		*adc_tm_dev;
+	struct mutex			jeita_configure_lock;
 };
 
 
@@ -1080,7 +1081,13 @@
 
 		if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
 						&& batt_present) {
+			pr_debug("enabling vadc notifications\n");
 			schedule_work(&chip->adc_measure_work);
+		} else if (chip->cool_bat_decidegc && chip->warm_bat_decidegc
+				&& !batt_present) {
+			qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev,
+					&chip->adc_param);
+			pr_debug("disabling vadc notifications\n");
 		}
 	}
 
@@ -1203,6 +1210,8 @@
 	case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL:
 	case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX:
 	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+	case POWER_SUPPLY_PROP_WARM_TEMP:
 		return 1;
 	default:
 		break;
@@ -1315,6 +1324,8 @@
 	POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
 	POWER_SUPPLY_PROP_CHARGE_FULL,
 	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_COOL_TEMP,
+	POWER_SUPPLY_PROP_WARM_TEMP,
 	POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL,
 	POWER_SUPPLY_PROP_CYCLE_COUNT,
 };
@@ -1688,6 +1699,12 @@
 	case POWER_SUPPLY_PROP_TEMP:
 		val->intval = get_prop_batt_temp(chip);
 		break;
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+		val->intval = chip->cool_bat_decidegc;
+		break;
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+		val->intval = chip->warm_bat_decidegc;
+		break;
 	case POWER_SUPPLY_PROP_CAPACITY:
 		val->intval = get_prop_capacity(chip);
 		break;
@@ -2388,10 +2405,74 @@
 		qpnp_chg_set_appropriate_vbatdet(chip);
 	}
 
+	pr_debug("warm %d, cool %d, low = %d deciDegC, high = %d deciDegC\n",
+			chip->bat_is_warm, chip->bat_is_cool,
+			chip->adc_param.low_temp, chip->adc_param.high_temp);
+
 	if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param))
 		pr_err("request ADC error\n");
+}
 
-	power_supply_changed(&chip->batt_psy);
+#define MIN_COOL_TEMP	-300
+#define MAX_WARM_TEMP	1000
+
+static int
+qpnp_chg_configure_jeita(struct qpnp_chg_chip *chip,
+		enum power_supply_property psp, int temp_degc)
+{
+	int rc = 0;
+
+	if ((temp_degc < MIN_COOL_TEMP) || (temp_degc > MAX_WARM_TEMP)) {
+		pr_err("Bad temperature request %d\n", temp_degc);
+		return -EINVAL;
+	}
+
+	mutex_lock(&chip->jeita_configure_lock);
+	switch (psp) {
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+		if (temp_degc >=
+			(chip->warm_bat_decidegc - HYSTERISIS_DECIDEGC)) {
+			pr_err("Can't set cool %d higher than warm %d - hysterisis %d\n",
+					temp_degc, chip->warm_bat_decidegc,
+					HYSTERISIS_DECIDEGC);
+			rc = -EINVAL;
+			goto mutex_unlock;
+		}
+		if (chip->bat_is_cool)
+			chip->adc_param.high_temp =
+				temp_degc + HYSTERISIS_DECIDEGC;
+		else if (!chip->bat_is_warm)
+			chip->adc_param.low_temp = temp_degc;
+
+		chip->cool_bat_decidegc = temp_degc;
+		break;
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+		if (temp_degc <=
+			(chip->cool_bat_decidegc + HYSTERISIS_DECIDEGC)) {
+			pr_err("Can't set warm %d higher than cool %d + hysterisis %d\n",
+					temp_degc, chip->warm_bat_decidegc,
+					HYSTERISIS_DECIDEGC);
+			rc = -EINVAL;
+			goto mutex_unlock;
+		}
+		if (chip->bat_is_warm)
+			chip->adc_param.low_temp =
+				temp_degc - HYSTERISIS_DECIDEGC;
+		else if (!chip->bat_is_cool)
+			chip->adc_param.high_temp = temp_degc;
+
+		chip->warm_bat_decidegc = temp_degc;
+		break;
+	default:
+		rc = -EINVAL;
+		goto mutex_unlock;
+	}
+
+	schedule_work(&chip->adc_measure_work);
+
+mutex_unlock:
+	mutex_unlock(&chip->jeita_configure_lock);
+	return rc;
 }
 
 static int
@@ -2431,8 +2512,15 @@
 {
 	struct qpnp_chg_chip *chip = container_of(psy, struct qpnp_chg_chip,
 								batt_psy);
+	int rc = 0;
 
 	switch (psp) {
+	case POWER_SUPPLY_PROP_COOL_TEMP:
+		rc = qpnp_chg_configure_jeita(chip, psp, val->intval);
+		break;
+	case POWER_SUPPLY_PROP_WARM_TEMP:
+		rc = qpnp_chg_configure_jeita(chip, psp, val->intval);
+		break;
 	case POWER_SUPPLY_PROP_CHARGING_ENABLED:
 		chip->charging_disabled = !(val->intval);
 		qpnp_chg_charge_en(chip, !chip->charging_disabled);
@@ -2452,7 +2540,7 @@
 	}
 
 	power_supply_changed(&chip->batt_psy);
-	return 0;
+	return rc;
 }
 
 static void
@@ -3176,6 +3264,7 @@
 		goto fail_chg_enable;
 	}
 
+	mutex_init(&chip->jeita_configure_lock);
 	/* Get all device tree properties */
 	rc = qpnp_charger_read_dt_props(chip);
 	if (rc)
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index de30fe0..5106c71 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -124,6 +124,8 @@
 	POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
 	POWER_SUPPLY_PROP_CAPACITY_LEVEL,
 	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_COOL_TEMP,
+	POWER_SUPPLY_PROP_WARM_TEMP,
 	POWER_SUPPLY_PROP_TEMP_AMBIENT,
 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
 	POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,