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

Commit 5cd45725 authored by tracychui(71954)'s avatar tracychui(71954) Committed by Gerrit Code Review
Browse files

Merge "Fixed USB preferences can not change in notifications area" into 8901-fairphone-p-vanilla

parents 8777c8f0 5fc29326
Loading
Loading
Loading
Loading
+239 −0
Original line number Diff line number Diff line
@@ -1578,7 +1578,234 @@ static int smb5_init_batt_psy(struct smb5 *chip)

	return rc;
}
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
/******************************
 * DUAL ROLE REGISTRATION *
 ******************************/
static enum dual_role_property smb5_dr_properties[] = {
	DUAL_ROLE_PROP_SUPPORTED_MODES,
	DUAL_ROLE_PROP_MODE,
	DUAL_ROLE_PROP_PR,
	DUAL_ROLE_PROP_DR,
};

static int smb5_dr_prop_writeable(struct dual_role_phy_instance *dual_role,
					enum dual_role_property prop)
{
	int rc;

	switch (prop) {
	case DUAL_ROLE_PROP_MODE:
	case DUAL_ROLE_PROP_PR:
	case DUAL_ROLE_PROP_DR:
		rc = 1;
		break;
	default:
		rc = 0;
	}
	return rc;
}

static int smb5_dr_set_property(struct dual_role_phy_instance *dual_role,
					enum dual_role_property prop,
					const unsigned int *val)
{
	int rc = 0, current_mode;
	struct smb_charger *chg = dual_role_get_drvdata(dual_role);

	if (!chg || (chg->connector_type != POWER_SUPPLY_CONNECTOR_TYPEC))
		return -EINVAL;

	current_mode = smblib_get_typec_mode(chg);

	switch (prop) {
	case DUAL_ROLE_PROP_MODE:
		/* Force role */
		mutex_lock(&chg->dr_lock);
		if (chg->dr_swap_in_progress) {
			pr_debug("Already in mode transition skipping request\n");
			mutex_unlock(&chg->dr_lock);
			return 0;
		}
		switch (*val) {
		case DUAL_ROLE_PROP_MODE_UFP:
			if (current_mode == DUAL_ROLE_PROP_MODE_UFP)
				chg->dr_mode = DUAL_ROLE_PROP_MODE_UFP;
			else {
				rc = smblib_force_dr_mode(chg,
						DUAL_ROLE_PROP_MODE_UFP);
				if (rc)
					pr_err("Failed to force UFP mode rc=%d\n",
									rc);
				else
					chg->dr_swap_in_progress = true;
			}
			break;
		case DUAL_ROLE_PROP_MODE_DFP:
			if (current_mode == DUAL_ROLE_PROP_MODE_DFP)
				chg->dr_mode = DUAL_ROLE_PROP_MODE_DFP;
			else {
				rc = smblib_force_dr_mode(chg,
						DUAL_ROLE_PROP_MODE_DFP);
				if (rc)
					pr_err("Failed to force DFP mode rc=%d\n",
									rc);
				else
					chg->dr_swap_in_progress = true;
			}
			break;
		default:
			pr_debug("Invalid role(not DFP/UFP) %d\n", *val);
			rc = -EINVAL;
		}
		mutex_unlock(&chg->dr_lock);

		/*
		 * schedule delayed work to check if device latched to the
		 * requested mode.
		 */
		if (!rc && chg->dr_swap_in_progress) {
			cancel_delayed_work_sync(&chg->role_reversal_check);
			vote(chg->awake_votable, DR_SWAP_VOTER, true, 0);
			schedule_delayed_work(&chg->role_reversal_check,
				msecs_to_jiffies(ROLE_REVERSAL_DELAY_MS));
		}
		break;
	case DUAL_ROLE_PROP_PR:
	case DUAL_ROLE_PROP_DR:
		/* Force role */
		mutex_lock(&chg->dr_lock);
		if (chg->dr_swap_in_progress) {
			pr_debug("Already in mode transition skipping request\n");
			mutex_unlock(&chg->dr_lock);
			return 0;
		}
		switch (*val) {
		case DUAL_ROLE_PROP_PR_SNK:
			if (current_mode == DUAL_ROLE_PROP_MODE_UFP)
				chg->dr_mode = DUAL_ROLE_PROP_MODE_UFP;
			else {
				rc = smblib_force_dr_mode(chg,
						DUAL_ROLE_PROP_MODE_UFP);
				if (rc)
					pr_err("Failed to force UFP mode rc=%d\n",
									rc);
				else
					chg->dr_swap_in_progress = true;
			}
			break;
		case DUAL_ROLE_PROP_PR_SRC:
			if (current_mode == DUAL_ROLE_PROP_MODE_DFP)
				chg->dr_mode = DUAL_ROLE_PROP_MODE_DFP;
			else {
				rc = smblib_force_dr_mode(chg,
						DUAL_ROLE_PROP_MODE_DFP);
				if (rc)
					pr_err("Failed to force DFP mode rc=%d\n",
									rc);
				else
					chg->dr_swap_in_progress = true;
			}
			break;
		default:
			pr_debug("Invalid role(not DFP/UFP) %d\n", *val);
			rc = -EINVAL;
		}
		mutex_unlock(&chg->dr_lock);

		/*
		 * schedule delayed work to check if device latched to the
		 * requested mode.
		 */
		if (!rc && chg->dr_swap_in_progress) {
			cancel_delayed_work_sync(&chg->role_reversal_check);
			vote(chg->awake_votable, DR_SWAP_VOTER, true, 0);
			schedule_delayed_work(&chg->role_reversal_check,
				msecs_to_jiffies(ROLE_REVERSAL_DELAY_MS));
		}
		break;
	default:
		pr_debug("Invalid DUAL ROLE request %d\n", prop);
		rc = -EINVAL;
	}

	return rc;
}

static int smb5_dr_get_property(struct dual_role_phy_instance *dual_role,
					enum dual_role_property prop,
					unsigned int *val)
{
	struct smb_charger *chg = dual_role_get_drvdata(dual_role);
	unsigned int mode, power_role, data_role;

	if (!chg || (chg->connector_type != POWER_SUPPLY_CONNECTOR_TYPEC))
		return -EINVAL;

	mode = smblib_get_typec_mode(chg);

	switch (mode) {
	case DUAL_ROLE_PROP_MODE_UFP:
		power_role = DUAL_ROLE_PROP_PR_SNK;
		data_role = DUAL_ROLE_PROP_DR_DEVICE;
		break;
	case DUAL_ROLE_PROP_MODE_DFP:
		power_role = DUAL_ROLE_PROP_PR_SRC;
		data_role = DUAL_ROLE_PROP_DR_HOST;
		break;
	default:
		power_role = DUAL_ROLE_PROP_PR_NONE;
		data_role = DUAL_ROLE_PROP_DR_NONE;
	};

	switch (prop) {
	case DUAL_ROLE_PROP_SUPPORTED_MODES:
		*val = chg->dual_role->desc->supported_modes;
		break;
	case DUAL_ROLE_PROP_MODE:
		*val = mode;
		break;
	case DUAL_ROLE_PROP_PR:
		*val = power_role;
		break;
	case DUAL_ROLE_PROP_DR:
		*val = data_role;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static const struct dual_role_phy_desc dr_desc = {
	.name = "otg_default",
	.supported_modes = DUAL_ROLE_SUPPORTED_MODES_DFP_AND_UFP,
	.properties = smb5_dr_properties,
	.num_properties = ARRAY_SIZE(smb5_dr_properties),
	.get_property = smb5_dr_get_property,
	.set_property = smb5_dr_set_property,
	.property_is_writeable = smb5_dr_prop_writeable,
};

static int smb5_init_dual_role_psy(struct smb5 *chip)
{
	struct smb_charger *chg = &chip->chg;
	int rc = 0;

	chg->dual_role = devm_dual_role_instance_register(chg->dev,
				&dr_desc);
	if (IS_ERR(chg->dual_role)) {
		pr_err("Couldn't register dual role\n");
		rc = PTR_ERR(chg->dual_role);
	} else {
		chg->dual_role->drv_data = chg;
		mutex_init(&chg->dr_lock);
	}

	return rc;
}
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
/******************************
 * VBUS REGULATOR REGISTRATION *
 ******************************/
@@ -2928,6 +3155,18 @@ static int smb5_probe(struct platform_device *pdev)
		goto cleanup;
	}

	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
	/*
	 * Register the Android dual-role class (/sys/class/dual_role_usb/)
	 */
	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) {
		rc = smb5_init_dual_role_psy(chip);
		if (rc < 0) {
			pr_err("Couldn't initialize batt psy rc=%d\n", rc);
			goto cleanup;
		}
	}
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	rc = smb5_determine_initial_status(chip);
	if (rc < 0) {
		pr_err("Couldn't determine initial status rc=%d\n",
+188 −4
Original line number Diff line number Diff line
@@ -2158,6 +2158,38 @@ static int smblib_get_prop_dfp_mode(struct smb_charger *chg)
	return POWER_SUPPLY_TYPEC_NONE;
}

/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
int smblib_get_typec_mode(struct smb_charger *chg)
{
	int rc;
	u8 stat = 0;

	rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
			rc);
	}
	smblib_dbg(chg, PR_REGISTER, "TYPE_C_STATE_MACHINE_STATUS_REG = 0x%02x\n",
			stat);

	if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) {
		rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
		if (rc < 0) {
			smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n",
				rc);
			return DUAL_ROLE_PROP_MODE_NONE;
		}
		smblib_dbg(chg, PR_REGISTER, "TYPE_C_MISC_STATUS_REG = 0x%02x\n",
				stat);
		if (stat & SNK_SRC_MODE_BIT)
			return DUAL_ROLE_PROP_MODE_DFP;
		else
			return DUAL_ROLE_PROP_MODE_UFP;
	} else
		return DUAL_ROLE_PROP_MODE_NONE;
}
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */

static int smblib_get_prop_typec_mode(struct smb_charger *chg)
{
	int rc;
@@ -3143,6 +3175,12 @@ void smblib_usb_plugin_locked(struct smb_charger *chg)
		smblib_micro_usb_plugin(chg, vbus_rising);

	power_supply_changed(chg->usb_psy);
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
		if (chg->dual_role)
		{
		  dual_role_instance_changed(chg->dual_role);
		}
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n",
					vbus_rising ? "attached" : "detached");
}
@@ -3434,7 +3472,12 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data)
	smblib_hvdcp_adaptive_voltage_change(chg);
	
	power_supply_changed(chg->usb_psy);

    /* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
	if (chg->dual_role)
	{
		dual_role_instance_changed(chg->dual_role);
	}
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	rc = smblib_read(chg, APSD_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
@@ -3662,7 +3705,12 @@ irqreturn_t typec_state_change_irq_handler(int irq, void *data)
				smblib_typec_mode_name[chg->typec_mode]);

	power_supply_changed(chg->usb_psy);

	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
	if (chg->dual_role)
	{
		dual_role_instance_changed(chg->dual_role);
	}
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	return IRQ_HANDLED;
}

@@ -3715,10 +3763,21 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data)
			chg->sink_src_mode = UNATTACHED_MODE;
			chg->early_usb_attach = false;
		}
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
		if (!chg->dr_swap_in_progress)
		{
			smblib_force_dr_mode(chg, DUAL_ROLE_PROP_MODE_NONE);
		}
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	}

	power_supply_changed(chg->usb_psy);

	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
	if (chg->dual_role)
	{
		dual_role_instance_changed(chg->dual_role);
	}	
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	return IRQ_HANDLED;
}

@@ -4332,6 +4391,121 @@ static void jeita_update_work(struct work_struct *work)
	chg->jeita_configured = true;
}

/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
/* requested mode */
static char *dual_mode_text[] = {
	"ufp", "dfp", "none"
};

int smblib_force_dr_mode(struct smb_charger *chg, int mode)
{
	int rc = 0;

	switch (mode) {
	case DUAL_ROLE_PROP_MODE_UFP:
		rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
				TYPEC_POWER_ROLE_CMD_MASK | EN_TRY_SNK_BIT,
				EN_SNK_ONLY_BIT);
		if (rc < 0) {
			dev_err(chg->dev,
				"Couldn't enable snk rc=%d\n", rc);
			return rc;
		}
		rc = smblib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT, 0);
		if (rc < 0) {
			smblib_err(chg, "Couldn't disable OTG rc=%d\n", rc);
			return rc;
		}
		break;
	case DUAL_ROLE_PROP_MODE_DFP:
		rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
				TYPEC_POWER_ROLE_CMD_MASK | EN_TRY_SNK_BIT,
				EN_SRC_ONLY_BIT);
		if (rc < 0) {
			dev_err(chg->dev,
				"Couldn't enable src rc=%d\n", rc);
			return rc;
		}
		rc = smblib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT,
							OTG_EN_BIT);
		if (rc < 0) {
			smblib_err(chg, "Couldn't enable OTG rc=%d\n", rc);
			return rc;
		}
		break;
	case DUAL_ROLE_PROP_MODE_NONE:
		rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
				TYPEC_POWER_ROLE_CMD_MASK | EN_TRY_SNK_BIT,
				EN_TRY_SNK_BIT);
		if (rc < 0) {
			dev_err(chg->dev,
				"Couldn't enable try.snk rc=%d\n", rc);
			return rc;
		}
		rc = smblib_masked_write(chg, DCDC_CMD_OTG_REG, OTG_EN_BIT, 0);
		if (rc < 0) {
			smblib_err(chg, "Couldn't disable OTG rc=%d\n", rc);
			return rc;
		}
		break;
	default:
		smblib_err(chg, "power role %d not supported\n", mode);
		return -EINVAL;
}

	if (chg->dr_mode != mode) {
		chg->dr_mode = mode;
		pr_debug("Forced mode: %s\n",
					dual_mode_text[chg->dr_mode]);
	}

	return rc;
}

static void smblib_dr_role_check_work(struct work_struct *work)
{
	struct smb_charger *chg = container_of(work, struct smb_charger,
						role_reversal_check.work);
	int rc, typec_mode;
	struct smb_irq_data irq_data = {chg, "determine-typec-status"};

	typec_mode = smblib_get_typec_mode(chg);
	mutex_lock(&chg->dr_lock);

	switch (chg->dr_mode) {
	case DUAL_ROLE_PROP_MODE_UFP:
		if (typec_mode != DUAL_ROLE_PROP_MODE_UFP) {
			pr_debug("Role-reversal not latched to UFP in %d msec resetting to DRP mode\n",
					ROLE_REVERSAL_DELAY_MS);
			rc = smblib_force_dr_mode(chg,
						DUAL_ROLE_PROP_MODE_NONE);
			if (rc)
				pr_err("Failed to set DRP mode rc=%d\n", rc);
		}
		chg->dr_swap_in_progress = false;
		break;
	case DUAL_ROLE_PROP_MODE_DFP:
		if (typec_mode != DUAL_ROLE_PROP_MODE_DFP) {
			pr_debug("Role-reversal not latched to DFP in %d msec resetting to DRP mode\n",
					ROLE_REVERSAL_DELAY_MS);
			rc = smblib_force_dr_mode(chg,
						DUAL_ROLE_PROP_MODE_NONE);
			if (rc)
				pr_err("Failed to set DRP mode rc=%d\n", rc);
		} else if (chg->sink_src_mode != SRC_MODE) {
			typec_attach_detach_irq_handler(0, &irq_data);
		}
		chg->dr_swap_in_progress = false;
		break;
	default:
		pr_debug("Already in DRP mode\n");
		break;
	}
	mutex_unlock(&chg->dr_lock);
	vote(chg->awake_votable, DR_SWAP_VOTER, false, 0);
}
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */

static int smblib_create_votables(struct smb_charger *chg)
{
	int rc = 0;
@@ -4441,6 +4615,9 @@ int smblib_init(struct smb_charger *chg)
	INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work);
	INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work);
	INIT_DELAYED_WORK(&chg->usbov_dbc_work, smblib_usbov_dbc_work);
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
	INIT_DELAYED_WORK(&chg->role_reversal_check, smblib_dr_role_check_work);
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */

	if (chg->wa_flags & CHG_TERMINATION_WA) {
		INIT_WORK(&chg->chg_termination_work,
@@ -4474,6 +4651,10 @@ int smblib_init(struct smb_charger *chg)
	chg->fake_batt_status = -EINVAL;
	chg->jeita_configured = false;
	chg->sink_src_mode = UNATTACHED_MODE;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
	chg->dr_mode = DUAL_ROLE_PROP_MODE_NONE;
	chg->dr_swap_in_progress = false;
 	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */

	switch (chg->mode) {
	case PARALLEL_MASTER:
@@ -4548,6 +4729,9 @@ int smblib_deinit(struct smb_charger *chg)
		cancel_delayed_work_sync(&chg->uusb_otg_work);
		cancel_delayed_work_sync(&chg->bb_removal_work);
		cancel_delayed_work_sync(&chg->usbov_dbc_work);
		/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
		cancel_delayed_work_sync(&chg->role_reversal_check);
		/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
		power_supply_unreg_notifier(&chg->nb);
		smblib_destroy_votables(chg);
		qcom_step_chg_deinit();
+28 −2
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@
#include <linux/regulator/consumer.h>
#include <linux/extcon.h>
#include <linux/alarmtimer.h>
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
#include <linux/usb/class-dual-role.h>
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
#include "storm-watch.h"

enum print_reason {
@@ -73,6 +76,9 @@ enum print_reason {
#define USBOV_DBC_VOTER			"USBOV_DBC_VOTER"
#define FCC_STEPPER_VOTER		"FCC_STEPPER_VOTER"
#define CHG_TERMINATION_VOTER		"CHG_TERMINATION_VOTER"
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
#define DR_SWAP_VOTER			"DR_SWAP_VOTER"
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */

#define BOOST_BACK_STORM_COUNT	3
#define WEAK_CHG_STORM_COUNT	8
@@ -87,6 +93,9 @@ enum print_reason {
#define TYPEC_DEFAULT_CURRENT_UA	900000
#define TYPEC_MEDIUM_CURRENT_UA		1500000
#define TYPEC_HIGH_CURRENT_UA		3000000
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
#define ROLE_REVERSAL_DELAY_MS	2000
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */

enum smb_mode {
	PARALLEL_MASTER = 0,
@@ -310,6 +319,9 @@ struct smb_charger {
	struct mutex		lock;
	struct mutex		ps_change_lock;
	struct mutex		vadc_lock;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
    struct mutex		dr_lock;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	
	/* power supplies */
	struct power_supply		*batt_psy;
@@ -318,6 +330,9 @@ struct smb_charger {
	struct power_supply		*bms_psy;
	struct power_supply		*usb_main_psy;
	struct power_supply		*usb_port_psy;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
	struct dual_role_phy_instance	*dual_role;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	enum power_supply_type		real_charger_type;

	/* notifiers */
@@ -355,6 +370,9 @@ struct smb_charger {
	struct delayed_work	uusb_otg_work;
	struct delayed_work	bb_removal_work;
	struct delayed_work	usbov_dbc_work;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
    struct delayed_work role_reversal_check;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	
	/* alarm */
	struct alarm		moisture_protection_alarm;
@@ -393,6 +411,10 @@ struct smb_charger {
	int			typec_mode;
	int			usb_icl_change_irq_enabled;
	u32			jeita_status;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
	u32			dr_mode;
	bool		dr_swap_in_progress;
	/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
	u8			float_cfg;
	bool			use_extcon;
	bool			otg_present;
@@ -596,4 +618,8 @@ int smblib_icl_override(struct smb_charger *chg, bool override);

int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area start */
int smblib_get_typec_mode(struct smb_charger *chg);
int smblib_force_dr_mode(struct smb_charger *chg, int mode);
/* [20190422][TracyChui]Fixed USB preferences can not change in notifications area end */
#endif /* __SMB5_CHARGER_H */