Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e1f8603 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "power: Add snapshot of SMB1360 and QPNP Linear charger"

parents cedce3c6 f0d35283
Loading
Loading
Loading
Loading
+26 −5
Original line number Diff line number Diff line
@@ -117,11 +117,28 @@ Optional Properties:
- qcom,config-hard-thresholds	This property indicates if cold and hot thresholds need be modified.
				If it's not defined, default temp thresholds will be used. If this
				defined, it's required to specify the "qcom,hot-bat-decidegc" and
				"qcom,cold-bat-decidegc" values.
- qcom,hot-bat-decidegc		Hot battery temperature in decidegC. This property must be
				out of range [0, 55].
- qcom,cold-bat-decidegc	Cold battery temperature in decidegC. This property must be
				out of range [0, 55].
				"qcom,cold-bat-decidegc" values. If this defined, the serial properties
				(qcom,otp-hard-jeita-config, qcom,otp-hot-bat-decidegc,
				qcom,otp-cold-bat-decidegc) mustn't be defined.
- qcom,hot-bat-decidegc		Hot battery temperature in decidegC. This property should only be
				defined when "qcom,config-hard-thresholds" defined, and the value
				must be out of range [0, 55].
- qcom,cold-bat-decidegc	Cold battery temperature in decidegC. This property should only be
				defined when "qcom,config-hard-thresholds" defined, and the value
				must be out of range [0, 55].
- qcom,otp-hard-jeita-config	This property indicates if cold and hot thresholds need be modified.
				If it's not defined, default temp thresholds [0, 55] will be used.
				If this defined, it's required to specify the "qcom,otp-hot-bat-decidegc"
				and "qcom,otp-cold-bat-decidegc" values. If this is defined, the serial
				properties (qcom,config-hard-thresholds, qcom,hot-bat-decidegc,
				qcom,cold-bat-decidegc) mustn't be defined.
- qcom,otp-hot-bat-decidegc	Hot battery temperature in decidegC. This property could only be
				defined when qcom,config-otp-hard-jeita exist.
- qcom,otp-cold-bat-decidegc	Cold battery temperature in decidegC. This property could only be
				defined when qcom,config-otp-hard-jeita exist.
- qcom,otp-hard-jeita-hysteresis This property contains two intergers to define the temperature
				hysteresis (in decidegC unit) for hard cold and hard hot.
				This property could only be defined when qcom,config-otp-hard-jeita exist.
- qcom,soft-jeita-supported	This property indicates whether soft jeita supported.
- qcom,warm-bat-decidegc	Warm battery temperature in decidegC. After hitting this threshold,
				"qcom,warm-bat-ma" defines maximum charging current and
@@ -211,6 +228,10 @@ Example:
			qcom,soft-jeita-supported;
			qcom,warm-bat-decidegc = <450>;
			qcom,cool-bat-decidegc = <100>;
			qcom,otp-hard-jeita-config;
			qcom,otp-hot-bat-decidegc = <550>;
			qcom,otp-cold-bat-decidegc = <0>;
			qcom,otp-hard-jeita-hysteresis = <0, 50>;
			qcom,warm-bat-mv = <4100>;
			qcom,cool-bat-mv = <4100>;
			qcom,warm-bat-ma = <750>;
+217 −67
Original line number Diff line number Diff line
@@ -40,8 +40,15 @@

/* USB CHARGER PATH peripheral register offsets */
#define USB_IN_VALID_MASK			BIT(1)
#define CHG_GONE_BIT				BIT(2)
#define USB_SUSP_REG				0x47
#define USB_SUSPEND_BIT				BIT(0)
#define USB_COMP_OVR1_REG			0xEA
#define USBIN_LLIMIT_OK_MASK			LBC_MASK(1, 0)
#define USBIN_LLIMIT_OK_NO_OVERRIDE		0x00
#define USBIN_LLIMIT_OK_OVERRIDE_1		0x03
#define USB_OVP_TST5_REG			0xE7
#define CHG_GONE_OK_EN_BIT			BIT(2)

/* CHARGER peripheral register offset */
#define CHG_OPTION_REG				0x08
@@ -71,6 +78,8 @@
#define CHG_PERPH_RESET_CTRL3_REG		0xDA
#define CHG_COMP_OVR1				0xEE
#define CHG_VBAT_DET_OVR_MASK			LBC_MASK(1, 0)
#define CHG_TEST_LOOP_REG			0xE5
#define VIN_MIN_LOOP_DISABLE_BIT		BIT(0)
#define OVERRIDE_0				0x2
#define OVERRIDE_NONE				0x0

@@ -147,6 +156,7 @@ enum {
	CURRENT = BIT(2),
	SOC	= BIT(3),
	PARALLEL = BIT(4),
	COLLAPSE = BIT(5),
};

enum bpd_type {
@@ -272,6 +282,7 @@ struct vddtrim_map vddtrim_map[] = {
 * @cfg_charger_detect_eoc:	charger can detect end of charging
 * @cfg_disable_vbatdet_based_recharge:	keep VBATDET comparator overriden to
 *				low and VBATDET irq disabled.
 * @cfg_collapsible_chgr_support: support collapsible charger
 * @cfg_chgr_led_support:	support charger led work.
 * @cfg_safe_current:		battery safety current setting
 * @cfg_hot_batt_p:		hot battery threshold setting
@@ -324,7 +335,7 @@ struct qpnp_lbc_chip {
	bool				fastchg_on;
	bool				cfg_use_external_charger;
	bool				cfg_chgr_led_support;
	bool				cfg_bms_controlled_charging;
	bool				non_collapsible_chgr_detected;
	unsigned int			cfg_warm_bat_chg_ma;
	unsigned int			cfg_cool_bat_chg_ma;
	unsigned int			cfg_safe_voltage_mv;
@@ -333,6 +344,7 @@ struct qpnp_lbc_chip {
	unsigned int			cfg_charger_detect_eoc;
	unsigned int			cfg_disable_vbatdet_based_recharge;
	unsigned int			cfg_batt_weak_voltage_uv;
	unsigned int			cfg_collapsible_chgr_support;
	unsigned int			cfg_warm_bat_mv;
	unsigned int			cfg_cool_bat_mv;
	unsigned int			cfg_hot_batt_p;
@@ -355,6 +367,7 @@ struct qpnp_lbc_chip {
	int				usb_psy_ma;
	int				delta_vddmax_uv;
	int				init_trim_uv;
	struct delayed_work		collapsible_detection_work;

	/* parallel-chg params */
	int				parallel_charging_enabled;
@@ -598,9 +611,10 @@ static u8 qpnp_lbc_get_trim_val(struct qpnp_lbc_chip *chip)
					return vddtrim_map[i + 1].trim_val;
			}
		}
		i = 0;
		break;
	case 1:
		for (i = TRIM_CENTER; i <= 7; i++) {
		for (i = TRIM_CENTER; i < ARRAY_SIZE(vddtrim_map); i++) {
			if (vddtrim_map[i].trim_uv < chip->delta_vddmax_uv) {
				delta_uv = AVG(vddtrim_map[i].trim_uv,
						vddtrim_map[i - 1].trim_uv);
@@ -610,6 +624,7 @@ static u8 qpnp_lbc_get_trim_val(struct qpnp_lbc_chip *chip)
					return vddtrim_map[i].trim_val;
			}
		}
		i = ARRAY_SIZE(vddtrim_map) - 1;
		break;
	}

@@ -634,6 +649,24 @@ static int qpnp_lbc_is_usb_chg_plugged_in(struct qpnp_lbc_chip *chip)
	return (usbin_valid_rt_sts & USB_IN_VALID_MASK) ? 1 : 0;
}

static int qpnp_lbc_is_chg_gone(struct qpnp_lbc_chip *chip)
{
	u8 rt_sts;
	int rc;

	rc = qpnp_lbc_read(chip, chip->usb_chgpth_base + INT_RT_STS_REG,
				&rt_sts, 1);
	if (rc) {
		pr_err("spmi read failed: addr=0x%04x, rc=%d\n",
				chip->usb_chgpth_base + INT_RT_STS_REG, rc);
		return rc;
	}

	pr_debug("rt_sts 0x%x\n", rt_sts);

	return (rt_sts & CHG_GONE_BIT) ? 1 : 0;
}

static int qpnp_lbc_charger_enable(struct qpnp_lbc_chip *chip, int reason,
					int enable)
{
@@ -700,10 +733,9 @@ static int qpnp_lbc_bat_if_configure_btc(struct qpnp_lbc_chip *chip)
		mask |= BTC_COLD_MASK;
	}

	if (!chip->cfg_btc_disabled) {
	mask |= BTC_COMP_EN_MASK;
	if (!chip->cfg_btc_disabled)
		btc_cfg |= BTC_COMP_EN_MASK;
	}

	pr_debug("BTC configuration mask=%x\n", btc_cfg);

@@ -716,6 +748,75 @@ static int qpnp_lbc_bat_if_configure_btc(struct qpnp_lbc_chip *chip)
	return rc;
}

static int qpnp_chg_collapsible_chgr_config(struct qpnp_lbc_chip *chip,
		bool enable)
{
	u8 reg_val;
	int rc;

	pr_debug("Configure for %scollapsible charger\n",
			enable ? "" : "non-");
	/*
	 * The flow to enable/disable the collapsible charger configuration:
	 *	Enable:  Override USBIN_LLIMIT_OK -->
	 *		 Disable VIN_MIN comparator -->
	 *		 Enable CHG_GONE comparator
	 *	Disable: Enable VIN_MIN comparator -->
	 *		 Enable USBIN_LLIMIT_OK -->
	 *		 Disable CHG_GONE comparator
	 */
	if (enable) {
		/* Override USBIN_LLIMIT_OK */
		reg_val = USBIN_LLIMIT_OK_OVERRIDE_1;
		rc = __qpnp_lbc_secure_masked_write(chip->spmi,
				chip->usb_chgpth_base,
				USB_COMP_OVR1_REG,
				USBIN_LLIMIT_OK_MASK, reg_val);
		if (rc) {
			pr_err("Failed to override USB_LLIMIT_OK rc = %d\n",
							rc);
			return rc;
		}
	}

	/* Configure VIN_MIN comparator */
	rc = __qpnp_lbc_secure_masked_write(chip->spmi,
			chip->chgr_base, CHG_TEST_LOOP_REG,
			VIN_MIN_LOOP_DISABLE_BIT,
			enable ? VIN_MIN_LOOP_DISABLE_BIT : 0);
	if (rc) {
		pr_err("Failed to %s VIN_MIN comparator rc = %d\n",
				enable ? "disable" : "enable", rc);
		return rc;
	}

	if (!enable) {
		/* Enable USBIN_LLIMIT_OK */
		reg_val = USBIN_LLIMIT_OK_NO_OVERRIDE;
		rc = __qpnp_lbc_secure_masked_write(chip->spmi,
				chip->usb_chgpth_base,
				USB_COMP_OVR1_REG,
				USBIN_LLIMIT_OK_MASK, reg_val);
		if (rc) {
			pr_err("Failed to override USB_LLIMIT_OK rc = %d\n",
							rc);
			return rc;
		}
	}

	/* Configure CHG_GONE comparator */
	reg_val = enable ? CHG_GONE_OK_EN_BIT : 0;
	rc = __qpnp_lbc_secure_masked_write(chip->spmi,
			chip->usb_chgpth_base, USB_OVP_TST5_REG,
			CHG_GONE_OK_EN_BIT, reg_val);
	if (rc) {
		pr_err("Failed to write CHG_GONE comparator rc = %d\n", rc);
		return rc;
	}

	return 0;
}

#define QPNP_LBC_VBATWEAK_MIN_UV        3000000
#define QPNP_LBC_VBATWEAK_MAX_UV        3581250
#define QPNP_LBC_VBATWEAK_STEP_UV       18750
@@ -1218,7 +1319,7 @@ static int get_prop_current_now(struct qpnp_lbc_chip *chip)
static int get_prop_capacity(struct qpnp_lbc_chip *chip)
{
	union power_supply_propval ret = {0,};
	int soc, battery_status, charger_in;
	int soc;

	if (chip->fake_battery_soc >= 0)
		return chip->fake_battery_soc;
@@ -1229,33 +1330,6 @@ static int get_prop_capacity(struct qpnp_lbc_chip *chip)
	if (chip->bms_psy) {
		chip->bms_psy->get_property(chip->bms_psy,
				POWER_SUPPLY_PROP_CAPACITY, &ret);
		mutex_lock(&chip->chg_enable_lock);
		if (chip->chg_done)
			chip->bms_psy->get_property(chip->bms_psy,
					POWER_SUPPLY_PROP_CAPACITY, &ret);
		battery_status = get_prop_batt_status(chip);
		charger_in = qpnp_lbc_is_usb_chg_plugged_in(chip);

		/* reset chg_done flag if capacity not 100% */
		if (ret.intval < 100 && chip->chg_done) {
			chip->chg_done = false;
			power_supply_changed(&chip->batt_psy);
		}

		if (battery_status != POWER_SUPPLY_STATUS_CHARGING
				&& charger_in
				&& !chip->cfg_charging_disabled
				&& chip->cfg_soc_resume_limit
				&& ret.intval <= chip->cfg_soc_resume_limit
				&& !chip->cfg_bms_controlled_charging) {
			pr_debug("resuming charging at %d%% soc\n",
					ret.intval);
			if (!chip->cfg_disable_vbatdet_based_recharge)
				qpnp_lbc_vbatdet_override(chip, OVERRIDE_0);
			qpnp_lbc_charger_enable(chip, SOC, 1);
		}
		mutex_unlock(&chip->chg_enable_lock);

		soc = ret.intval;
		if (soc == 0) {
			if (!qpnp_lbc_is_usb_chg_plugged_in(chip))
@@ -1523,10 +1597,10 @@ static int qpnp_batt_power_set_property(struct power_supply *psy,
	switch (psp) {
	case POWER_SUPPLY_PROP_STATUS:
		mutex_lock(&chip->chg_enable_lock);

		if (val->intval == POWER_SUPPLY_STATUS_FULL &&
				!chip->cfg_float_charge) {

		switch (val->intval) {
		case POWER_SUPPLY_STATUS_FULL:
			if (chip->cfg_float_charge)
				break;
			/* Disable charging */
			rc = qpnp_lbc_charger_enable(chip, SOC, 0);
			if (rc)
@@ -1551,17 +1625,13 @@ static int qpnp_batt_power_set_property(struct power_supply *psy,
					qpnp_lbc_enable_irq(chip,
						&chip->irqs[CHG_VBAT_DET_LO]);
			}

		}

		if (chip->cfg_bms_controlled_charging) {
			switch (val->intval) {
			break;
		case POWER_SUPPLY_STATUS_CHARGING:
			chip->chg_done = false;
			pr_debug("resuming charging by bms\n");
			if (!chip->cfg_disable_vbatdet_based_recharge)
					qpnp_lbc_vbatdet_override(chip,
								OVERRIDE_0);
				qpnp_lbc_vbatdet_override(chip, OVERRIDE_0);

			qpnp_lbc_charger_enable(chip, SOC, 1);
			break;
		case POWER_SUPPLY_STATUS_DISCHARGING:
@@ -1572,8 +1642,6 @@ static int qpnp_batt_power_set_property(struct power_supply *psy,
		default:
			break;
		}
		}

		mutex_unlock(&chip->chg_enable_lock);
		break;
	case POWER_SUPPLY_PROP_COOL_TEMP:
@@ -2105,7 +2173,6 @@ static int show_lbc_config(struct seq_file *m, void *data)
			"cfg_use_fake_battery\t=\t%d\n"
			"cfg_use_external_charger\t=\t%d\n"
			"cfg_chgr_led_support\t=\t%d\n"
			"cfg_bms_controlled_charging\t=\t%d\n"
			"cfg_warm_bat_chg_ma\t=\t%d\n"
			"cfg_cool_bat_chg_ma\t=\t%d\n"
			"cfg_safe_voltage_mv\t=\t%d\n"
@@ -2113,6 +2180,7 @@ static int show_lbc_config(struct seq_file *m, void *data)
			"cfg_min_voltage_mv\t=\t%d\n"
			"cfg_charger_detect_eoc\t=\t%d\n"
			"cfg_disable_vbatdet_based_recharge\t=\t%d\n"
			"cfg_collapsible_chgr_support\t=\t%d\n"
			"cfg_batt_weak_voltage_uv\t=\t%d\n"
			"cfg_warm_bat_mv\t=\t%d\n"
			"cfg_cool_bat_mv\t=\t%d\n"
@@ -2131,7 +2199,6 @@ static int show_lbc_config(struct seq_file *m, void *data)
			chip->cfg_use_fake_battery,
			chip->cfg_use_external_charger,
			chip->cfg_chgr_led_support,
			chip->cfg_bms_controlled_charging,
			chip->cfg_warm_bat_chg_ma,
			chip->cfg_cool_bat_chg_ma,
			chip->cfg_safe_voltage_mv,
@@ -2139,6 +2206,7 @@ static int show_lbc_config(struct seq_file *m, void *data)
			chip->cfg_min_voltage_mv,
			chip->cfg_charger_detect_eoc,
			chip->cfg_disable_vbatdet_based_recharge,
			chip->cfg_collapsible_chgr_support,
			chip->cfg_batt_weak_voltage_uv,
			chip->cfg_warm_bat_mv,
			chip->cfg_cool_bat_mv,
@@ -2284,9 +2352,10 @@ static int qpnp_charger_read_dt_props(struct qpnp_lbc_chip *chip)
			of_property_read_bool(chip->spmi->dev.of_node,
					"qcom,chgr-led-support");

	chip->cfg_bms_controlled_charging =
	/* Get the collapsible charger support property */
	chip->cfg_collapsible_chgr_support =
			of_property_read_bool(chip->spmi->dev.of_node,
					"qcom,bms-controlled-charging");
					"qcom,collapsible-chgr-support");

	/* Disable charging when faking battery values */
	if (chip->cfg_use_fake_battery)
@@ -2343,17 +2412,50 @@ static int qpnp_charger_read_dt_props(struct qpnp_lbc_chip *chip)
			chip->cfg_charging_disabled,
			chip->cfg_use_fake_battery,
			chip->cfg_float_charge);
	pr_debug("charger-detect-eoc=%d, disable-vbatdet-based-recharge=%d, chgr-led-support=%d, bms-controlled-charging=%d\n",
	pr_debug("charger-detect-eoc=%d, disable-vbatdet-based-recharge=%d, chgr-led-support=%d\n",
			chip->cfg_charger_detect_eoc,
			chip->cfg_disable_vbatdet_based_recharge,
			chip->cfg_chgr_led_support,
			chip->cfg_bms_controlled_charging);
	pr_debug("use-external-charger=%d, thermal_levels=%d\n",
			chip->cfg_chgr_led_support);
	pr_debug("collapsible-chg-support=%d, use-external-charger=%d, thermal_levels=%d\n",
			chip->cfg_collapsible_chgr_support,
			chip->cfg_use_external_charger,
			chip->cfg_thermal_levels);
	return rc;
}

#define CHG_REMOVAL_DETECT_DLY_MS	300
static irqreturn_t qpnp_lbc_chg_gone_irq_handler(int irq, void *_chip)
{
	struct qpnp_lbc_chip *chip = _chip;
	int chg_gone;

	if (chip->cfg_collapsible_chgr_support) {
		chg_gone = qpnp_lbc_is_chg_gone(chip);
		pr_debug("chg-gone triggered, rt_sts: %d\n", chg_gone);
		if (chg_gone) {
			/*
			 * Disable charger to prevent fastchg irq storming
			 * if a non-collapsible charger is being used.
			 */
			pr_debug("disable charging for non-collapsbile charger\n");
			qpnp_lbc_charger_enable(chip, COLLAPSE, 0);
			qpnp_lbc_disable_irq(chip, &chip->irqs[USBIN_VALID]);
			qpnp_lbc_disable_irq(chip, &chip->irqs[USB_CHG_GONE]);
			qpnp_chg_collapsible_chgr_config(chip, 0);
			/*
			 * Check after a delay if the charger is still
			 * inserted. It decides if a non-collapsible
			 * charger is being used, or charger has been
			 * removed.
			 */
			schedule_delayed_work(&chip->collapsible_detection_work,
				msecs_to_jiffies(CHG_REMOVAL_DETECT_DLY_MS));
		}
	}

	return IRQ_HANDLED;
}

static irqreturn_t qpnp_lbc_usbin_valid_irq_handler(int irq, void *_chip)
{
	struct qpnp_lbc_chip *chip = _chip;
@@ -2372,6 +2474,11 @@ static irqreturn_t qpnp_lbc_usbin_valid_irq_handler(int irq, void *_chip)
			qpnp_lbc_set_appropriate_current(chip);
			spin_unlock_irqrestore(&chip->ibat_change_lock,
								flags);
			if (chip->cfg_collapsible_chgr_support)
				chip->non_collapsible_chgr_detected = false;

			if (chip->supported_feature_flag & VDD_TRIM_SUPPORTED)
				alarm_try_to_cancel(&chip->vddtrim_alarm);
		} else {
			/*
			 * Override VBAT_DET comparator to start charging
@@ -2380,6 +2487,16 @@ static irqreturn_t qpnp_lbc_usbin_valid_irq_handler(int irq, void *_chip)
			if (!chip->cfg_disable_vbatdet_based_recharge)
				qpnp_lbc_vbatdet_override(chip, OVERRIDE_0);

			/*
			 * If collapsible charger supported, enable chgr_gone
			 * irq, and configure for collapsible charger.
			 */
			if (chip->cfg_collapsible_chgr_support &&
					!chip->non_collapsible_chgr_detected) {
				qpnp_lbc_enable_irq(chip,
						&chip->irqs[USB_CHG_GONE]);
				qpnp_chg_collapsible_chgr_config(chip, 1);
			}
			/*
			 * Enable SOC based charging to make sure
			 * charging gets enabled on USB insertion
@@ -2685,6 +2802,9 @@ static int qpnp_lbc_request_irqs(struct qpnp_lbc_chip *chip)
	SPMI_REQUEST_IRQ(chip, USBIN_VALID, rc, usbin_valid, 0,
			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 1);

	SPMI_REQUEST_IRQ(chip, USB_CHG_GONE, rc, chg_gone, 0,
			IRQF_TRIGGER_RISING, 1);

	SPMI_REQUEST_IRQ(chip, USB_OVER_TEMP, rc, usb_overtemp, 0,
			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 0);

@@ -2720,6 +2840,8 @@ static int qpnp_lbc_get_irqs(struct qpnp_lbc_chip *chip, u8 subtype,
						USBIN_VALID, usbin-valid);
		SPMI_GET_IRQ_RESOURCE(chip, rc, spmi_resource,
						USB_OVER_TEMP, usb-over-temp);
		SPMI_GET_IRQ_RESOURCE(chip, rc, spmi_resource,
						USB_CHG_GONE, chg-gone);
		break;
	};

@@ -2735,9 +2857,34 @@ static void determine_initial_status(struct qpnp_lbc_chip *chip)
	 * Set USB psy online to avoid userspace from shutting down if battery
	 * capacity is at zero and no chargers online.
	 */
	if (chip->usb_present)
	if (chip->usb_present) {
		if (chip->cfg_collapsible_chgr_support &&
				!chip->non_collapsible_chgr_detected) {
			qpnp_lbc_enable_irq(chip,
					&chip->irqs[USB_CHG_GONE]);
			qpnp_chg_collapsible_chgr_config(chip, 1);
		}
		power_supply_set_online(chip->usb_psy, 1);
	}
}

static void qpnp_lbc_collapsible_detection_work(struct work_struct *work)
{
	struct delayed_work *dwork = to_delayed_work(work);
	struct qpnp_lbc_chip *chip = container_of(dwork,
			struct qpnp_lbc_chip,
			collapsible_detection_work);

	if (qpnp_lbc_is_usb_chg_plugged_in(chip)) {
		chip->non_collapsible_chgr_detected = true;
		pr_debug("Non-collapsible charger detected\n");
	} else {
		chip->non_collapsible_chgr_detected = false;
		pr_debug("Charger removal detected\n");
	}
	qpnp_lbc_charger_enable(chip, COLLAPSE, 1);
	qpnp_lbc_enable_irq(chip, &chip->irqs[USBIN_VALID]);
}

#define IBAT_TRIM			-300
static void qpnp_lbc_vddtrim_work_fn(struct work_struct *work)
@@ -3041,6 +3188,8 @@ static int qpnp_lbc_main_probe(struct spmi_device *spmi)
	spin_lock_init(&chip->irq_lock);
	INIT_WORK(&chip->vddtrim_work, qpnp_lbc_vddtrim_work_fn);
	alarm_init(&chip->vddtrim_alarm, ALARM_REALTIME, vddtrim_callback);
	INIT_DELAYED_WORK(&chip->collapsible_detection_work,
			qpnp_lbc_collapsible_detection_work);

	/* Get all device-tree properties */
	rc = qpnp_charger_read_dt_props(chip);
@@ -3226,6 +3375,7 @@ static int qpnp_lbc_remove(struct spmi_device *spmi)
		alarm_cancel(&chip->vddtrim_alarm);
		cancel_work_sync(&chip->vddtrim_work);
	}
	cancel_delayed_work_sync(&chip->collapsible_detection_work);
	debugfs_remove_recursive(chip->debug_root);
	if (chip->bat_if_base)
		power_supply_unregister(&chip->batt_psy);
+59 −23
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@
#include <linux/qpnp/qpnp-adc.h>
#include <linux/of_batterydata.h>
#include <linux/batterydata-interface.h>
#include <linux/qpnp-revid.h>
#include <linux/qpnp/qpnp-revid.h>
#include <uapi/linux/vm_bms.h>

#define _BMS_MASK(BITS, POS) \
@@ -244,6 +244,7 @@ struct qpnp_bms_chip {
	u16				charge_cycles;
	unsigned int			start_soc;
	unsigned int			end_soc;
	unsigned int			chg_start_soc;

	struct bms_battery_data		*batt_data;
	struct bms_dt_cfg		dt;
@@ -962,7 +963,7 @@ static int lookup_soc_ocv(struct qpnp_bms_chip *chip, int ocv_uv, int batt_temp)

	if (chip->batt_data->ibat_acc_lut) {
		/* Apply  ACC logic only if we discharging */
		if (!is_battery_charging(chip) && chip->current_now > 0) {
		if (chip->current_now > 0) {

			/*
			 * IBAT averaging is disabled at low temp.
@@ -1607,7 +1608,9 @@ static int report_vm_bms_soc(struct qpnp_bms_chip *chip)
	 * avoid overflows when charging continues for extended periods
	 */
	if (charging && chip->last_soc != -EINVAL) {
		if (chip->charge_start_tm_sec == 0) {
		if (chip->charge_start_tm_sec == 0 ||
			(chip->catch_up_time_sec == 0 &&
				(abs(soc - chip->last_soc) >= MIN_SOC_UUC))) {
			/*
			 * calculating soc for the first time
			 * after start of chg. Initialize catchup time
@@ -1619,17 +1622,25 @@ static int report_vm_bms_soc(struct qpnp_bms_chip *chip)
			else
				chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX;

			chip->chg_start_soc = chip->last_soc;

			if (chip->catch_up_time_sec < 0)
				chip->catch_up_time_sec = 0;
			chip->charge_start_tm_sec = last_change_sec;

			pr_debug("chg_start_soc=%d charge_start_tm_sec=%d catch_up_time_sec=%d\n",
				chip->chg_start_soc, chip->charge_start_tm_sec,
						chip->catch_up_time_sec);
		}

		charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec
				- chip->charge_start_tm_sec);

		/* end catchup if calculated soc and last soc are same */
		if (chip->last_soc == soc)
		if (chip->last_soc == soc) {
			chip->catch_up_time_sec = 0;
			chip->chg_start_soc = chip->last_soc;
		}
	}

	if (chip->last_soc != -EINVAL) {
@@ -1647,7 +1658,7 @@ static int report_vm_bms_soc(struct qpnp_bms_chip *chip)
		else if (chip->last_soc < soc && soc != 100)
			soc = scale_soc_while_chg(chip, charge_time_sec,
					chip->catch_up_time_sec,
					soc, chip->last_soc);
					soc, chip->chg_start_soc);

		/*
		 * if the battery is close to cutoff or if the batt_temp
@@ -1963,6 +1974,11 @@ static void calculate_reported_soc(struct qpnp_bms_chip *chip)
{
	union power_supply_propval ret = {0,};

	if (chip->last_soc < 0) {
		pr_debug("last_soc is not ready, return\n");
		return;
	}

	if (chip->reported_soc > chip->last_soc) {
		/*send DISCHARGING status if the reported_soc drops from 100 */
		if (chip->reported_soc == 100) {
@@ -2022,13 +2038,26 @@ static int clamp_soc_based_on_voltage(struct qpnp_bms_chip *chip, int soc)
	}
}

static void battery_voltage_check(struct qpnp_bms_chip *chip)
{
	int rc, vbat_uv = 0;

	rc = get_battery_voltage(chip, &vbat_uv);
	if (rc < 0) {
		pr_err("Failed to read battery-voltage rc=%d\n", rc);
	} else {
		very_low_voltage_check(chip, vbat_uv);
		cv_voltage_check(chip, vbat_uv);
	}
}

#define UI_SOC_CATCHUP_TIME	(60)
static void monitor_soc_work(struct work_struct *work)
{
	struct qpnp_bms_chip *chip = container_of(work,
				struct qpnp_bms_chip,
				monitor_soc_work.work);
	int rc, vbat_uv = 0, new_soc = 0, batt_temp;
	int rc, new_soc = 0, batt_temp;

	bms_stay_awake(&chip->vbms_soc_wake_source);

@@ -2044,13 +2073,7 @@ static void monitor_soc_work(struct work_struct *work)
		chip->last_soc = -EINVAL;
		new_soc = 100;
	} else {
		rc = get_battery_voltage(chip, &vbat_uv);
		if (rc < 0) {
			pr_err("Failed to read battery-voltage rc=%d\n", rc);
		} else {
			very_low_voltage_check(chip, vbat_uv);
			cv_voltage_check(chip, vbat_uv);
		}
		battery_voltage_check(chip);

		if (chip->dt.cfg_use_voltage_soc) {
			calculate_soc_from_voltage(chip);
@@ -2075,6 +2098,11 @@ static void monitor_soc_work(struct work_struct *work)
				pr_debug("SOC changed! new_soc=%d prev_soc=%d\n",
						new_soc, chip->calculated_soc);
				chip->calculated_soc = new_soc;
				/*
				 * To recalculate the catch-up time, clear it
				 * when SOC changes.
				 */
				chip->catch_up_time_sec = 0;

				if (chip->calculated_soc == 100)
					/* update last_soc immediately */
@@ -2180,6 +2208,7 @@ static enum power_supply_property bms_power_props[] = {
	POWER_SUPPLY_PROP_STATUS,
	POWER_SUPPLY_PROP_RESISTANCE,
	POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE,
	POWER_SUPPLY_PROP_RESISTANCE_NOW,
	POWER_SUPPLY_PROP_CURRENT_NOW,
	POWER_SUPPLY_PROP_VOLTAGE_OCV,
	POWER_SUPPLY_PROP_HI_POWER,
@@ -2232,6 +2261,12 @@ static int qpnp_vm_bms_power_get_property(struct power_supply *psy,
		if (chip->dt.cfg_r_conn_mohm > 0)
			val->intval += chip->dt.cfg_r_conn_mohm;
		break;
	case POWER_SUPPLY_PROP_RESISTANCE_NOW:
		rc = get_batt_therm(chip, &value);
		if (rc < 0)
			value = BMS_DEFAULT_TEMP;
		val->intval = get_rbatt(chip, chip->calculated_soc, value);
		break;
	case POWER_SUPPLY_PROP_CURRENT_NOW:
		val->intval = get_prop_bms_current_now(chip);
		break;
@@ -2442,6 +2477,10 @@ static void qpnp_vm_bms_ext_power_changed(struct power_supply *psy)
	battery_status_check(chip);
	battery_insertion_check(chip);

	mutex_lock(&chip->last_soc_mutex);
	battery_voltage_check(chip);
	mutex_unlock(&chip->last_soc_mutex);

	if (chip->reported_soc_in_use)
		reported_soc_check_status(chip);
}
@@ -2931,7 +2970,7 @@ static int calculate_initial_aging_comp(struct qpnp_bms_chip *chip)

static int bms_load_hw_defaults(struct qpnp_bms_chip *chip)
{
	u8 val, state, bms_en = 0;
	u8 val, bms_en = 0;
	u32 interval[2], count[2], fifo[2];
	int rc;

@@ -3029,14 +3068,10 @@ static int bms_load_hw_defaults(struct qpnp_bms_chip *chip)
	get_fifo_length(chip, S2_STATE, &fifo[1]);

	/* Force the BMS state to S2 at boot-up */
	rc = get_fsm_state(chip, &state);
	if (rc)
		pr_err("Unable to get FSM state rc=%d\n", rc);
	if (rc || (state != S2_STATE)) {
		pr_debug("Forcing S2 state\n");
	rc = force_fsm_state(chip, S2_STATE);
		if (rc)
			pr_err("Unable to set FSM state rc=%d\n", rc);
	if (rc) {
		pr_err("Unable to force S2 state rc=%d\n", rc);
		return rc;
	}

	rc = qpnp_read_wrapper(chip, &bms_en, chip->base + EN_CTL_REG, 1);
@@ -3453,7 +3488,8 @@ static int set_battery_data(struct qpnp_bms_chip *chip)
	rc = of_batterydata_read_data(node, batt_data, battery_id);
	if (rc || !batt_data->pc_temp_ocv_lut
		|| !batt_data->fcc_temp_lut
		|| !batt_data->rbatt_sf_lut) {
		|| !batt_data->rbatt_sf_lut
		|| !batt_data->ibat_acc_lut) {
		pr_err("battery data load failed\n");
		devm_kfree(chip->dev, batt_data->fcc_temp_lut);
		devm_kfree(chip->dev, batt_data->pc_temp_ocv_lut);
+763 −194

File changed.

Preview size limit exceeded, changes collapsed.

+15 −0
Original line number Diff line number Diff line
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * 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 <uapi/linux/batterydata-interface.h>

int config_battery_data(struct bms_battery_data *profile);
Loading