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

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

Merge "power: smblib: SW implementation of typeC try.SNK"

parents ca42b890 29f23820
Loading
Loading
Loading
Loading
+16 −10
Original line number Diff line number Diff line
@@ -188,6 +188,11 @@ static int __weak_chg_icl_ua = 500000;
module_param_named(
	weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600);

static int __try_sink_enabled = 1;
module_param_named(
	try_sink_enabled, __try_sink_enabled, int, 0600
);

#define MICRO_1P5A		1500000
#define MICRO_P1A		100000
#define OTG_DEFAULT_DEGLITCH_TIME_MS	50
@@ -1037,7 +1042,10 @@ static int smb2_batt_get_prop(struct power_supply *psy,
		val->intval = 0;
		break;
	case POWER_SUPPLY_PROP_DIE_HEALTH:
		if (chg->die_health == -EINVAL)
			rc = smblib_get_prop_die_health(chg, val);
		else
			val->intval = chg->die_health;
		break;
	case POWER_SUPPLY_PROP_DP_DM:
		val->intval = chg->pulse_cnt;
@@ -1145,6 +1153,10 @@ static int smb2_batt_set_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
		rc = smblib_set_prop_input_current_limited(chg, val);
		break;
	case POWER_SUPPLY_PROP_DIE_HEALTH:
		chg->die_health = val->intval;
		power_supply_changed(chg->batt_psy);
		break;
	default:
		rc = -EINVAL;
	}
@@ -1166,6 +1178,7 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy,
	case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED:
	case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED:
	case POWER_SUPPLY_PROP_SW_JEITA_ENABLED:
	case POWER_SUPPLY_PROP_DIE_HEALTH:
		return 1;
	default:
		break;
@@ -1647,15 +1660,6 @@ static int smb2_init_hw(struct smb2 *chip)
		return rc;
	}

	/* disable SW STAT override */
	rc = smblib_masked_write(chg, STAT_CFG_REG,
				 STAT_SW_OVERRIDE_CFG_BIT, 0);
	if (rc < 0) {
		dev_err(chg->dev, "Couldn't disable SW STAT override rc=%d\n",
			rc);
		return rc;
	}

	/* disable h/w autonomous parallel charging control */
	rc = smblib_masked_write(chg, MISC_CFG_REG,
				 STAT_PARALLEL_1400MA_EN_CFG_BIT, 0);
@@ -2244,9 +2248,11 @@ static int smb2_probe(struct platform_device *pdev)
	chg->dev = &pdev->dev;
	chg->param = v1_params;
	chg->debug_mask = &__debug_mask;
	chg->try_sink_enabled = &__try_sink_enabled;
	chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
	chg->mode = PARALLEL_MASTER;
	chg->irq_info = smb2_irqs;
	chg->die_health = -EINVAL;
	chg->name = "PMI";

	chg->regmap = dev_get_regmap(chg->dev->parent, NULL);
+198 −3
Original line number Diff line number Diff line
@@ -143,6 +143,23 @@ int smblib_icl_override(struct smb_charger *chg, bool override)
	return rc;
}

int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override)
{
	int rc;

	/* override  = 1, SW STAT override; override = 0, HW auto mode */
	rc = smblib_masked_write(chg, STAT_CFG_REG,
				STAT_SW_OVERRIDE_CFG_BIT,
				override ? STAT_SW_OVERRIDE_CFG_BIT : 0);
	if (rc < 0) {
		dev_err(chg->dev, "Couldn't configure SW STAT override rc=%d\n",
			rc);
		return rc;
	}

	return rc;
}

/********************
 * REGISTER GETTERS *
 ********************/
@@ -584,8 +601,10 @@ static int smblib_notifier_call(struct notifier_block *nb,
			schedule_work(&chg->bms_update_work);
	}

	if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel"))
	if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) {
		chg->pl.psy = psy;
		schedule_work(&chg->pl_update_work);
	}

	return NOTIFY_OK;
}
@@ -3773,8 +3792,165 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data)
	return IRQ_HANDLED;
}

static int typec_try_sink(struct smb_charger *chg)
{
	union power_supply_propval val;
	bool debounce_done, vbus_detected, sink;
	u8 stat;
	int exit_mode = ATTACHED_SRC, rc;

	/* ignore typec interrupt while try.snk WIP */
	chg->try_sink_active = true;

	/* force SNK mode */
	val.intval = POWER_SUPPLY_TYPEC_PR_SINK;
	rc = smblib_set_prop_typec_power_role(chg, &val);
	if (rc < 0) {
		smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
		goto try_sink_exit;
	}

	/* reduce Tccdebounce time to ~20ms */
	rc = smblib_masked_write(chg, MISC_CFG_REG,
			TCC_DEBOUNCE_20MS_BIT, TCC_DEBOUNCE_20MS_BIT);
	if (rc < 0) {
		smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);
		goto try_sink_exit;
	}

	/*
	 * give opportunity to the other side to be a SRC,
	 * for tDRPTRY + Tccdebounce time
	 */
	msleep(100);

	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
				rc);
		goto try_sink_exit;
	}

	debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;

	if (!debounce_done)
		/*
		 * The other side didn't switch to source, either it
		 * is an adamant sink or is removed go back to showing Rp
		 */
		goto try_wait_src;

	/*
	 * We are in force sink mode and the other side has switched to
	 * showing Rp. Config DRP in case the other side removes Rp so we
	 * can quickly (20ms) switch to showing our Rp. Note that the spec
	 * needs us to show Rp for 80mS while the drp DFP residency is just
	 * 54mS. But 54mS is plenty time for us to react and force Rp for
	 * the remaining 26mS.
	 */
	val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
	rc = smblib_set_prop_typec_power_role(chg, &val);
	if (rc < 0) {
		smblib_err(chg, "Couldn't set DFP mode rc=%d\n",
				rc);
		goto try_sink_exit;
	}

	/*
	 * while other side is Rp, wait for VBUS from it; exit if other side
	 * removes Rp
	 */
	do {
		rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
		if (rc < 0) {
			smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
					rc);
			goto try_sink_exit;
		}

		debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;
		vbus_detected = stat & TYPEC_VBUS_STATUS_BIT;

		/* Successfully transitioned to ATTACHED.SNK */
		if (vbus_detected && debounce_done) {
			exit_mode = ATTACHED_SINK;
			goto try_sink_exit;
		}

		/*
		 * Ensure sink since drp may put us in source if other
		 * side switches back to Rd
		 */
		sink = !(stat &  UFP_DFP_MODE_STATUS_BIT);

		usleep_range(1000, 2000);
	} while (debounce_done && sink);

try_wait_src:
	/*
	 * Transition to trywait.SRC state. check if other side still wants
	 * to be SNK or has been removed.
	 */
	val.intval = POWER_SUPPLY_TYPEC_PR_SOURCE;
	rc = smblib_set_prop_typec_power_role(chg, &val);
	if (rc < 0) {
		smblib_err(chg, "Couldn't set UFP mode rc=%d\n", rc);
		goto try_sink_exit;
	}

	/* Need to be in this state for tDRPTRY time, 75ms~150ms */
	msleep(80);

	rc = smblib_read(chg, TYPE_C_STATUS_4_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
		goto try_sink_exit;
	}

	debounce_done = stat & TYPEC_DEBOUNCE_DONE_STATUS_BIT;

	if (debounce_done)
		/* the other side wants to be a sink */
		exit_mode = ATTACHED_SRC;
	else
		/* the other side is detached */
		exit_mode = UNATTACHED_SINK;

try_sink_exit:
	/* release forcing of SRC/SNK mode */
	val.intval = POWER_SUPPLY_TYPEC_PR_DUAL;
	rc = smblib_set_prop_typec_power_role(chg, &val);
	if (rc < 0)
		smblib_err(chg, "Couldn't set DFP mode rc=%d\n", rc);

	/* revert Tccdebounce time back to ~120ms */
	rc = smblib_masked_write(chg, MISC_CFG_REG, TCC_DEBOUNCE_20MS_BIT, 0);
	if (rc < 0)
		smblib_err(chg, "Couldn't set MISC_CFG_REG rc=%d\n", rc);

	chg->try_sink_active = false;

	return exit_mode;
}

static void typec_sink_insertion(struct smb_charger *chg)
{
	int exit_mode;

	/*
	 * Try.SNK entry status - ATTACHWAIT.SRC state and detected Rd-open
	 * or RD-Ra for TccDebounce time.
	 */

	if (*chg->try_sink_enabled) {
		exit_mode = typec_try_sink(chg);

		if (exit_mode != ATTACHED_SRC) {
			smblib_usb_typec_change(chg);
			return;
		}
	}

	/* when a sink is inserted we should not wait on hvdcp timeout to
	 * enable pd
	 */
@@ -4041,7 +4217,7 @@ static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
				smblib_typec_mode_name[chg->typec_mode]);
}

static void smblib_usb_typec_change(struct smb_charger *chg)
void smblib_usb_typec_change(struct smb_charger *chg)
{
	int rc;

@@ -4077,7 +4253,8 @@ irqreturn_t smblib_handle_usb_typec_change(int irq, void *data)
		return IRQ_HANDLED;
	}

	if (chg->cc2_detach_wa_active || chg->typec_en_dis_active) {
	if (chg->cc2_detach_wa_active || chg->typec_en_dis_active ||
					 chg->try_sink_active) {
		smblib_dbg(chg, PR_INTERRUPT, "Ignoring since %s active\n",
			chg->cc2_detach_wa_active ?
			"cc2_detach_wa" : "typec_en_dis");
@@ -4282,6 +4459,14 @@ static void bms_update_work(struct work_struct *work)
		power_supply_changed(chg->batt_psy);
}

static void pl_update_work(struct work_struct *work)
{
	struct smb_charger *chg = container_of(work, struct smb_charger,
						pl_update_work);

	smblib_stat_sw_override_cfg(chg, false);
}

static void clear_hdc_work(struct work_struct *work)
{
	struct smb_charger *chg = container_of(work, struct smb_charger,
@@ -4812,6 +4997,7 @@ int smblib_init(struct smb_charger *chg)
	mutex_init(&chg->otg_oc_lock);
	mutex_init(&chg->vconn_oc_lock);
	INIT_WORK(&chg->bms_update_work, bms_update_work);
	INIT_WORK(&chg->pl_update_work, pl_update_work);
	INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work);
	INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work);
	INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work);
@@ -4860,6 +5046,14 @@ int smblib_init(struct smb_charger *chg)

		chg->bms_psy = power_supply_get_by_name("bms");
		chg->pl.psy = power_supply_get_by_name("parallel");
		if (chg->pl.psy) {
			rc = smblib_stat_sw_override_cfg(chg, false);
			if (rc < 0) {
				smblib_err(chg,
					"Couldn't config stat sw rc=%d\n", rc);
				return rc;
			}
		}
		break;
	case PARALLEL_SLAVE:
		break;
@@ -4876,6 +5070,7 @@ int smblib_deinit(struct smb_charger *chg)
	switch (chg->mode) {
	case PARALLEL_MASTER:
		cancel_work_sync(&chg->bms_update_work);
		cancel_work_sync(&chg->pl_update_work);
		cancel_work_sync(&chg->rdstd_cc2_detach_work);
		cancel_delayed_work_sync(&chg->hvdcp_detect_work);
		cancel_delayed_work_sync(&chg->clear_hdc_work);
+13 −0
Original line number Diff line number Diff line
@@ -130,6 +130,12 @@ enum smb_irq_index {
	SMB_IRQ_MAX,
};

enum try_sink_exit_mode {
	ATTACHED_SRC = 0,
	ATTACHED_SINK,
	UNATTACHED_SINK,
};

struct smb_irq_info {
	const char			*name;
	const irq_handler_t		handler;
@@ -232,6 +238,7 @@ struct smb_charger {
	struct smb_params	param;
	struct smb_iio		iio;
	int			*debug_mask;
	int			*try_sink_enabled;
	enum smb_mode		mode;
	struct smb_chg_freq	chg_freq;
	int			smb_version;
@@ -287,6 +294,7 @@ struct smb_charger {

	/* work */
	struct work_struct	bms_update_work;
	struct work_struct	pl_update_work;
	struct work_struct	rdstd_cc2_detach_work;
	struct delayed_work	hvdcp_detect_work;
	struct delayed_work	ps_change_timeout_work;
@@ -342,6 +350,7 @@ struct smb_charger {
	u32			wa_flags;
	bool			cc2_detach_wa_active;
	bool			typec_en_dis_active;
	bool			try_sink_active;
	int			boost_current_ua;
	int			temp_speed_reading_count;

@@ -355,6 +364,8 @@ struct smb_charger {
	/* qnovo */
	int			usb_icl_delta_ua;
	int			pulse_cnt;

	int			die_health;
};

int smblib_read(struct smb_charger *chg, u16 addr, u8 *val);
@@ -523,6 +534,8 @@ int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg,
				union power_supply_propval *val);
int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg,
				const union power_supply_propval *val);
int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override);
void smblib_usb_typec_change(struct smb_charger *chg);

int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
+32 −3
Original line number Diff line number Diff line
@@ -146,6 +146,8 @@ struct smb1355 {

	struct power_supply	*parallel_psy;
	struct pmic_revid_data	*pmic_rev_id;

	int			c_health;
};

static bool is_secure(struct smb1355 *chip, int addr)
@@ -434,7 +436,10 @@ static int smb1355_parallel_get_prop(struct power_supply *psy,
		val->intval = POWER_SUPPLY_PL_USBMID_USBMID;
		break;
	case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
		if (chip->c_health == -EINVAL)
			val->intval = smb1355_get_prop_connector_health(chip);
		else
			val->intval = chip->c_health;
		break;
	default:
		pr_err_ratelimited("parallel psy get prop %d not supported\n",
@@ -497,6 +502,10 @@ static int smb1355_parallel_set_prop(struct power_supply *psy,
		rc = smb1355_set_charge_param(chip, &chip->param.fcc,
						val->intval);
		break;
	case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
		chip->c_health = val->intval;
		power_supply_changed(chip->parallel_psy);
		break;
	default:
		pr_debug("parallel power supply set prop %d not supported\n",
			prop);
@@ -509,6 +518,13 @@ static int smb1355_parallel_set_prop(struct power_supply *psy,
static int smb1355_parallel_prop_is_writeable(struct power_supply *psy,
					      enum power_supply_property prop)
{
	switch (prop) {
	case POWER_SUPPLY_PROP_CONNECTOR_HEALTH:
		return 1;
	default:
		break;
	}

	return 0;
}

@@ -714,6 +730,7 @@ static int smb1355_probe(struct platform_device *pdev)

	chip->dev = &pdev->dev;
	chip->param = v1_params;
	chip->c_health = -EINVAL;
	chip->name = "smb1355";
	mutex_init(&chip->write_lock);

@@ -763,6 +780,17 @@ static int smb1355_remove(struct platform_device *pdev)
	return 0;
}

static void smb1355_shutdown(struct platform_device *pdev)
{
	struct smb1355 *chip = platform_get_drvdata(pdev);
	int rc;

	/* disable parallel charging path */
	rc = smb1355_set_parallel_charging(chip, true);
	if (rc < 0)
		pr_err("Couldn't disable parallel path rc=%d\n", rc);
}

static struct platform_driver smb1355_driver = {
	.driver	= {
		.name		= "qcom,smb1355-charger",
@@ -771,6 +799,7 @@ static struct platform_driver smb1355_driver = {
	},
	.probe		= smb1355_probe,
	.remove		= smb1355_remove,
	.shutdown	= smb1355_shutdown,
};
module_platform_driver(smb1355_driver);