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

Commit 1f373e21 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "dt-bindings: qpnp-smb5: Support changing DCIN ICL"

parents 7aae1597 2dc8fdd0
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -350,6 +350,13 @@ Charger specific properties:
  Value type: bool
  Definition: Boolean flag which when present disables FCC restriction.

- qcom,wls-current-max-ua
  Usage:      optional
  Value type: <u32>
  Definition: Upper limit of charging current supplied by the wireless
		charger. If left unspecified, the HW min value of 1.5 A is
		applied by default.

=============================================
Second Level Nodes - SMB5 Charger Peripherals
=============================================
+15 −9
Original line number Diff line number Diff line
@@ -160,7 +160,7 @@ static struct smb_params smb5_pm8150b_params = {
		.name   = "DC input current limit",
		.reg    = DCDC_CFG_REF_MAX_PSNS_REG,
		.min_u  = 0,
		.max_u  = 1500000,
		.max_u  = DCIN_ICL_MAX_UA,
		.step_u = 50000,
	},
	.jeita_cc_comp_hot	= {
@@ -396,7 +396,7 @@ static int smb5_parse_dt(struct smb5 *chip)
{
	struct smb_charger *chg = &chip->chg;
	struct device_node *node = chg->dev->of_node;
	int rc, byte_len;
	int rc, byte_len, tmp;

	if (!node) {
		pr_err("device tree node missing\n");
@@ -653,6 +653,12 @@ static int smb5_parse_dt(struct smb5 *chip)
	if (chg->chg_param.hvdcp3_max_icl_ua <= 0)
		chg->chg_param.hvdcp3_max_icl_ua = MICRO_3PA;

	chg->wls_icl_ua = DCIN_ICL_MAX_UA;
	rc = of_property_read_u32(node, "qcom,wls-current-max-ua",
			&tmp);
	if (!rc && tmp < DCIN_ICL_MAX_UA)
		chg->wls_icl_ua = tmp;

	return 0;
}

@@ -1468,15 +1474,14 @@ static int smb5_dc_set_prop(struct power_supply *psy,
static int smb5_dc_prop_is_writeable(struct power_supply *psy,
		enum power_supply_property psp)
{
	int rc;

	switch (psp) {
	case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION:
		return 1;
	default:
		rc = 0;
		break;
	}

	return rc;
	return 0;
}

static const struct power_supply_desc dc_psy_desc = {
@@ -2458,8 +2463,8 @@ static int smb5_init_dc_peripheral(struct smb_charger *chg)
	if (chg->chg_param.smb_version == PMI632_SUBTYPE)
		return 0;

	/* set DC icl_max 1A */
	rc = smblib_set_charge_param(chg, &chg->param.dc_icl, 1000000);
	/* Set DCIN ICL to 100 mA */
	rc = smblib_set_charge_param(chg, &chg->param.dc_icl, DCIN_ICL_MIN_UA);
	if (rc < 0) {
		dev_err(chg->dev, "Couldn't set dc_icl rc=%d\n", rc);
		return rc;
@@ -3096,7 +3101,8 @@ static struct smb_irq_info smb5_irqs[] = {
	},
	[DCIN_UV_IRQ] = {
		.name		= "dcin-uv",
		.handler	= default_irq_handler,
		.handler	= dcin_uv_irq_handler,
		.wake		= true,
	},
	[DCIN_OV_IRQ] = {
		.name		= "dcin-ov",
+192 −3
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/iio/consumer.h>
#include <linux/pmic-voter.h>
#include <linux/of_batterydata.h>
#include <linux/ktime.h>
#include "smb5-lib.h"
#include "smb5-reg.h"
#include "schgm-flash.h"
@@ -2982,12 +2983,15 @@ int smblib_get_prop_dc_voltage_now(struct smb_charger *chg,
	rc = power_supply_get_property(chg->wls_psy,
				POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION,
				val);
	if (rc < 0)
	if (rc < 0) {
		dev_err(chg->dev, "Couldn't get POWER_SUPPLY_PROP_VOLTAGE_REGULATION, rc=%d\n",
				rc);
		return rc;
	}

	return rc;
}

/*******************
 * DC PSY SETTERS *
 *******************/
@@ -2998,6 +3002,7 @@ int smblib_set_prop_dc_current_max(struct smb_charger *chg,
	return smblib_set_charge_param(chg, &chg->param.dc_icl, val->intval);
}

#define DCIN_AICL_RERUN_DELAY_MS	5000
int smblib_set_prop_voltage_wls_output(struct smb_charger *chg,
				    const union power_supply_propval *val)
{
@@ -3016,7 +3021,19 @@ int smblib_set_prop_voltage_wls_output(struct smb_charger *chg,
		dev_err(chg->dev, "Couldn't set POWER_SUPPLY_PROP_VOLTAGE_REGULATION, rc=%d\n",
				rc);

	smblib_dbg(chg, PR_WLS, "Set WLS output voltage %d\n", val->intval);
	smblib_dbg(chg, PR_WLS, "%d\n", val->intval);

	/*
	 * When WLS VOUT goes down, the power-constrained adaptor may be able
	 * to supply more current, so allow it to do so.
	 */
	if ((val->intval > 0) && (val->intval < chg->last_wls_vout)) {
		/* Rerun AICL once after 10 s */
		alarm_start_relative(&chg->dcin_aicl_alarm,
				ms_to_ktime(DCIN_AICL_RERUN_DELAY_MS));
	}

	chg->last_wls_vout = val->intval;

	return rc;
}
@@ -5914,6 +5931,151 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data)
	return IRQ_HANDLED;
}

static void dcin_aicl(struct smb_charger *chg)
{
	int rc, icl, icl_save;
	int input_present;

	/*
	 * Hold awake votable to prevent pm_relax being called prior to
	 * completion of this work.
	 */
	vote(chg->awake_votable, DCIN_AICL_VOTER, true, 0);

increment:
	mutex_lock(&chg->dcin_aicl_lock);

	rc = smblib_get_charge_param(chg, &chg->param.dc_icl, &icl);
	if (rc < 0)
		goto unlock;

	if (icl == chg->wls_icl_ua) {
		/* Upper limit reached; do nothing */
		smblib_dbg(chg, PR_WLS, "hit max ICL: stop\n");
		goto unlock;
	}

	icl = min(chg->wls_icl_ua, icl + DCIN_ICL_STEP_UA);
	icl_save = icl;

	rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl);
	if (rc < 0)
		goto unlock;

	mutex_unlock(&chg->dcin_aicl_lock);

	smblib_dbg(chg, PR_WLS, "icl: %d mA\n", (icl / 1000));

	/* Check to see if DC is still present before and after sleep */
	rc = smblib_is_input_present(chg, &input_present);
	if (!(input_present & INPUT_PRESENT_DC) || rc < 0)
		goto unvote;

	/*
	 * Wait awhile to check for any DCIN_UVs (the UV handler reduces the
	 * ICL). If the adaptor collapses, the ICL read after waking up will be
	 * lesser, indicating that the AICL process is complete.
	 */
	msleep(500);

	rc = smblib_is_input_present(chg, &input_present);
	if (!(input_present & INPUT_PRESENT_DC) || rc < 0)
		goto unvote;

	mutex_lock(&chg->dcin_aicl_lock);

	rc = smblib_get_charge_param(chg, &chg->param.dc_icl, &icl);
	if (rc < 0)
		goto unlock;

	if (icl < icl_save) {
		smblib_dbg(chg, PR_WLS, "done: icl: %d mA\n", (icl / 1000));
		goto unlock;
	}

	mutex_unlock(&chg->dcin_aicl_lock);

	goto increment;
unlock:
	mutex_unlock(&chg->dcin_aicl_lock);
unvote:
	vote(chg->awake_votable, DCIN_AICL_VOTER, false, 0);
}

static void dcin_aicl_work(struct work_struct *work)
{
	struct smb_charger *chg = container_of(work, struct smb_charger,
						dcin_aicl_work);
	dcin_aicl(chg);
}

static enum alarmtimer_restart dcin_aicl_alarm_cb(struct alarm *alarm,
							ktime_t now)
{
	struct smb_charger *chg = container_of(alarm, struct smb_charger,
					dcin_aicl_alarm);

	smblib_dbg(chg, PR_WLS, "rerunning DCIN AICL\n");

	pm_stay_awake(chg->dev);
	schedule_work(&chg->dcin_aicl_work);

	return ALARMTIMER_NORESTART;
}

static void dcin_icl_decrement(struct smb_charger *chg)
{
	int rc, icl;
	ktime_t now = ktime_get();

	rc = smblib_get_charge_param(chg, &chg->param.dc_icl, &icl);
	if (rc < 0) {
		smblib_err(chg, "reading DCIN ICL failed: %d\n", rc);
		return;
	}

	if (icl == DCIN_ICL_MIN_UA) {
		/* Cannot possibly decrease ICL any further - do nothing */
		smblib_dbg(chg, PR_WLS, "hit min ICL: stop\n");
		return;
	}

	/* Reduce ICL by 100 mA if 3 UVs happen in a row */
	if (ktime_us_delta(now, chg->dcin_uv_last_time) > (200 * 1000)) {
		chg->dcin_uv_count = 0;
	} else if (chg->dcin_uv_count == 3) {
		icl -= DCIN_ICL_STEP_UA;

		smblib_dbg(chg, PR_WLS, "icl: %d mA\n", (icl / 1000));
		rc = smblib_set_charge_param(chg, &chg->param.dc_icl, icl);
		if (rc < 0) {
			smblib_err(chg, "setting DCIN ICL failed: %d\n", rc);
			return;
		}

		chg->dcin_uv_count = 0;
	}

	chg->dcin_uv_last_time = now;
}

irqreturn_t dcin_uv_irq_handler(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;
	struct smb_charger *chg = irq_data->parent_data;

	mutex_lock(&chg->dcin_aicl_lock);

	chg->dcin_uv_count++;
	smblib_dbg(chg, (PR_WLS | PR_INTERRUPT), "DCIN UV count: %d\n",
			chg->dcin_uv_count);
	dcin_icl_decrement(chg);

	mutex_unlock(&chg->dcin_aicl_lock);

	return IRQ_HANDLED;
}

irqreturn_t dc_plugin_irq_handler(int irq, void *data)
{
	struct smb_irq_data *irq_data = data;
@@ -5939,6 +6101,18 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data)
	vbus_present = input_present & INPUT_PRESENT_USB;

	if (dcin_present && !vbus_present) {
		cancel_work_sync(&chg->dcin_aicl_work);

		/* Reset DCIN ICL to 100 mA */
		mutex_lock(&chg->dcin_aicl_lock);
		rc = smblib_set_charge_param(chg, &chg->param.dc_icl,
				DCIN_ICL_MIN_UA);
		mutex_unlock(&chg->dcin_aicl_lock);
		if (rc < 0)
			return IRQ_HANDLED;

		smblib_dbg(chg, (PR_WLS | PR_INTERRUPT), "reset: icl: 100 mA\n");

		if (chg->sec_cp_present) {
			pval.intval = wireless_vout;
			rc = smblib_set_prop_voltage_wls_output(chg, &pval);
@@ -5963,6 +6137,8 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data)
				dev_err(chg->dev, "Couldn't set dc voltage to 5 V rc=%d\n",
					rc);
		}

		schedule_work(&chg->dcin_aicl_work);
	} else {
		if (chg->cp_reason == POWER_SUPPLY_CP_WIRELESS) {
			sec_charger = chg->sec_pl_present ?
@@ -5976,11 +6152,13 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data)
		}

		vote(chg->dc_suspend_votable, CHG_TERMINATION_VOTER, false, 0);

		chg->last_wls_vout = 0;
	}

	power_supply_changed(chg->dc_psy);

	smblib_dbg(chg, PR_WLS, "dcin_present= %d, usbin_present= %d, cp_reason = %d\n",
	smblib_dbg(chg, (PR_WLS | PR_INTERRUPT), "dcin_present= %d, usbin_present= %d, cp_reason = %d\n",
			dcin_present, vbus_present, chg->cp_reason);

	return IRQ_HANDLED;
@@ -7167,9 +7345,11 @@ int smblib_init(struct smb_charger *chg)
	mutex_init(&chg->smb_lock);
	mutex_init(&chg->irq_status_lock);
	spin_lock_init(&chg->typec_pr_lock);
	mutex_init(&chg->dcin_aicl_lock);
	INIT_WORK(&chg->bms_update_work, bms_update_work);
	INIT_WORK(&chg->pl_update_work, pl_update_work);
	INIT_WORK(&chg->jeita_update_work, jeita_update_work);
	INIT_WORK(&chg->dcin_aicl_work, dcin_aicl_work);
	INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
	INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work);
	INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work);
@@ -7213,6 +7393,14 @@ int smblib_init(struct smb_charger *chg)
		}
	}

	if (alarmtimer_get_rtcdev()) {
		alarm_init(&chg->dcin_aicl_alarm, ALARM_REALTIME,
				dcin_aicl_alarm_cb);
	} else {
		smblib_err(chg, "Failed to initialize dcin aicl alarm\n");
		return -ENODEV;
	}

	chg->fake_capacity = -EINVAL;
	chg->fake_input_current_limited = -EINVAL;
	chg->fake_batt_status = -EINVAL;
@@ -7318,6 +7506,7 @@ int smblib_deinit(struct smb_charger *chg)
		cancel_work_sync(&chg->bms_update_work);
		cancel_work_sync(&chg->jeita_update_work);
		cancel_work_sync(&chg->pl_update_work);
		cancel_work_sync(&chg->dcin_aicl_work);
		cancel_delayed_work_sync(&chg->clear_hdc_work);
		cancel_delayed_work_sync(&chg->icl_change_work);
		cancel_delayed_work_sync(&chg->pl_enable_work);
+12 −1
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ enum print_reason {
#define DETACH_DETECT_VOTER		"DETACH_DETECT_VOTER"
#define CC_MODE_VOTER			"CC_MODE_VOTER"
#define MAIN_FCC_VOTER			"MAIN_FCC_VOTER"
#define DCIN_AICL_VOTER			"DCIN_AICL_VOTER"

#define BOOST_BACK_STORM_COUNT	3
#define WEAK_CHG_STORM_COUNT	8
@@ -101,6 +102,9 @@ enum print_reason {
#define TYPEC_DEFAULT_CURRENT_UA	900000
#define TYPEC_MEDIUM_CURRENT_UA		1500000
#define TYPEC_HIGH_CURRENT_UA		3000000
#define DCIN_ICL_MIN_UA			100000
#define DCIN_ICL_MAX_UA			1500000
#define DCIN_ICL_STEP_UA		100000

#define ROLE_REVERSAL_DELAY_MS		2000

@@ -391,6 +395,7 @@ struct smb_charger {
	struct mutex		dr_lock;
	struct mutex		irq_status_lock;
	spinlock_t		typec_pr_lock;
	struct mutex		dcin_aicl_lock;

	/* power supplies */
	struct power_supply		*batt_psy;
@@ -443,6 +448,7 @@ struct smb_charger {
	struct work_struct	jeita_update_work;
	struct work_struct	moisture_protection_work;
	struct work_struct	chg_termination_work;
	struct work_struct	dcin_aicl_work;
	struct delayed_work	ps_change_timeout_work;
	struct delayed_work	clear_hdc_work;
	struct delayed_work	icl_change_work;
@@ -460,6 +466,7 @@ struct smb_charger {
	struct alarm		lpd_recheck_timer;
	struct alarm		moisture_protection_alarm;
	struct alarm		chg_termination_alarm;
	struct alarm		dcin_aicl_alarm;

	struct charger_param	chg_param;
	/* secondary charger config */
@@ -553,6 +560,7 @@ struct smb_charger {
	int			init_thermal_ua;
	u32			comp_clamp_level;
	bool			hvdcp3_standalone_config;
	int			wls_icl_ua;

	/* workaround flag */
	u32			wa_flags;
@@ -583,7 +591,9 @@ struct smb_charger {
	u32			irq_status;

	/* wireless */
	int			wireless_vout;
	int			dcin_uv_count;
	ktime_t			dcin_uv_last_time;
	int			last_wls_vout;
};

int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -633,6 +643,7 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data);
irqreturn_t icl_change_irq_handler(int irq, void *data);
irqreturn_t typec_state_change_irq_handler(int irq, void *data);
irqreturn_t typec_attach_detach_irq_handler(int irq, void *data);
irqreturn_t dcin_uv_irq_handler(int irq, void *data);
irqreturn_t dc_plugin_irq_handler(int irq, void *data);
irqreturn_t high_duty_cycle_irq_handler(int irq, void *data);
irqreturn_t switcher_power_ok_irq_handler(int irq, void *data);