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

Commit 616ae4d5 authored by Umang Agrawal's avatar Umang Agrawal
Browse files

power: smb5: Add moisture detection support for uUSB connector



Presence of moisture expedites the corrosion of Type-C/uUSB ID pins
due to constant DRP toggling. To reduce the effect of corrosion,
set DRP toggling duty cycle to 1% and suspend USB input on water
detection.

Use property MOISTURE_DETECTED to reflect moisture detection status.

Change-Id: I3bb41564cf67127ae2c0bb27089a1e8b5d722df6
Signed-off-by: default avatarUmang Agrawal <uagrawal@codeaurora.org>
parent 936238b7
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -257,6 +257,12 @@ Charger specific properties:
  Definition: Boolean flag which when present disables suspend on collapse
  Definition: Boolean flag which when present disables suspend on collapse
		feature of charger hardware.
		feature of charger hardware.


- qcom,uusb-moisture-protection-enable
	Usage:      optional
	Value type: bool
	Definition: Boolean flag which when present enables mositure protection
		    feature for uUSB connector type.

=============================================
=============================================
Second Level Nodes - SMB5 Charger Peripherals
Second Level Nodes - SMB5 Charger Peripherals
=============================================
=============================================
+41 −0
Original line number Original line Diff line number Diff line
@@ -258,6 +258,8 @@ static int smb5_chg_config_init(struct smb5 *chip)
		chg->param = smb5_pm8150b_params;
		chg->param = smb5_pm8150b_params;
		chg->name = "pm6150_charger";
		chg->name = "pm6150_charger";
		chg->wa_flags |= SW_THERM_REGULATION_WA;
		chg->wa_flags |= SW_THERM_REGULATION_WA;
		if (pmic_rev_id->rev4 >= 2)
			chg->uusb_moisture_protection_enabled = true;
		chg->main_fcc_max = PM6150_MAX_FCC_UA;
		chg->main_fcc_max = PM6150_MAX_FCC_UA;
		break;
		break;
	case PMI632_SUBTYPE:
	case PMI632_SUBTYPE:
@@ -444,6 +446,11 @@ static int smb5_parse_dt(struct smb5 *chip)
	chg->fcc_stepper_enable = of_property_read_bool(node,
	chg->fcc_stepper_enable = of_property_read_bool(node,
					"qcom,fcc-stepping-enable");
					"qcom,fcc-stepping-enable");


	chg->uusb_moisture_protection_enabled =
				chg->uusb_moisture_protection_enabled &&
				of_property_read_bool(node,
				"qcom,uusb-moisture-protection-enable");

	/* Extract ADC channels */
	/* Extract ADC channels */
	rc = smblib_get_iio_channel(chg, "mid_voltage", &chg->iio.mid_chan);
	rc = smblib_get_iio_channel(chg, "mid_voltage", &chg->iio.mid_chan);
	if (rc < 0)
	if (rc < 0)
@@ -530,6 +537,7 @@ static enum power_supply_property smb5_usb_props[] = {
	POWER_SUPPLY_PROP_SMB_EN_MODE,
	POWER_SUPPLY_PROP_SMB_EN_MODE,
	POWER_SUPPLY_PROP_SMB_EN_REASON,
	POWER_SUPPLY_PROP_SMB_EN_REASON,
	POWER_SUPPLY_PROP_SCOPE,
	POWER_SUPPLY_PROP_SCOPE,
	POWER_SUPPLY_PROP_MOISTURE_DETECTED,
};
};


static int smb5_usb_get_prop(struct power_supply *psy,
static int smb5_usb_get_prop(struct power_supply *psy,
@@ -671,6 +679,9 @@ static int smb5_usb_get_prop(struct power_supply *psy,
	case POWER_SUPPLY_PROP_SMB_EN_REASON:
	case POWER_SUPPLY_PROP_SMB_EN_REASON:
		val->intval = chg->cp_reason;
		val->intval = chg->cp_reason;
		break;
		break;
	case POWER_SUPPLY_PROP_MOISTURE_DETECTED:
		val->intval = chg->moisture_present;
		break;
	default:
	default:
		pr_err("get prop %d is not supported in usb\n", psp);
		pr_err("get prop %d is not supported in usb\n", psp);
		rc = -EINVAL;
		rc = -EINVAL;
@@ -1662,6 +1673,36 @@ static int smb5_configure_micro_usb(struct smb_charger *chg)
		return rc;
		return rc;
	}
	}


	if (chg->uusb_moisture_protection_enabled) {
		/* Enable moisture detection interrupt */
		rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
				TYPEC_WATER_DETECTION_INT_EN_BIT,
				TYPEC_WATER_DETECTION_INT_EN_BIT);
		if (rc < 0) {
			dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n",
				rc);
			return rc;
		}

		/* Enable uUSB factory mode */
		rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
					EN_MICRO_USB_FACTORY_MODE_BIT,
					EN_MICRO_USB_FACTORY_MODE_BIT);
		if (rc < 0) {
			dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n",
				rc);
			return rc;
		}

		/* Disable periodic monitoring of CC_ID pin */
		rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0);
		if (rc < 0) {
			dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n",
				rc);
			return rc;
		}
	}

	return rc;
	return rc;
}
}


+221 −3
Original line number Original line Diff line number Diff line
@@ -1322,6 +1322,100 @@ int smblib_toggle_smb_en(struct smb_charger *chg, int toggle)
	return rc;
	return rc;
}
}


/****************************
 * uUSB Moisture Protection *
 ****************************/
#define MICRO_USB_DETECTION_ON_TIME_20_MS 0x08
#define MICRO_USB_DETECTION_PERIOD_X_100 0x03
#define U_USB_STATUS_WATER_PRESENT 0x00
static int smblib_set_moisture_protection(struct smb_charger *chg,
				bool enable)
{
	int rc = 0;

	if (chg->moisture_present == enable) {
		smblib_dbg(chg, PR_MISC, "No change in moisture protection status\n");
		return rc;
	}

	if (enable) {
		chg->moisture_present = true;

		/* Disable uUSB factory mode detection */
		rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
					EN_MICRO_USB_FACTORY_MODE_BIT, 0);
		if (rc < 0) {
			smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n",
				rc);
			return rc;
		}

		/* Disable moisture detection and uUSB state change interrupt */
		rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
					TYPEC_WATER_DETECTION_INT_EN_BIT |
					MICRO_USB_STATE_CHANGE_INT_EN_BIT, 0);
		if (rc < 0) {
			smblib_err(chg, "Couldn't disable moisture detection interrupt rc=%d\n",
			rc);
			return rc;
		}

		/* Set 1% duty cycle on ID detection */
		rc = smblib_masked_write(chg,
					TYPEC_U_USB_WATER_PROTECTION_CFG_REG,
					EN_MICRO_USB_WATER_PROTECTION_BIT |
					MICRO_USB_DETECTION_ON_TIME_CFG_MASK |
					MICRO_USB_DETECTION_PERIOD_CFG_MASK,
					EN_MICRO_USB_WATER_PROTECTION_BIT |
					MICRO_USB_DETECTION_ON_TIME_20_MS |
					MICRO_USB_DETECTION_PERIOD_X_100);
		if (rc < 0) {
			smblib_err(chg, "Couldn't set 1 percent CC_ID duty cycle rc=%d\n",
				rc);
			return rc;
		}

		vote(chg->usb_icl_votable, MOISTURE_VOTER, true, 0);
	} else {
		chg->moisture_present = false;
		vote(chg->usb_icl_votable, MOISTURE_VOTER, false, 0);

		/* Enable moisture detection and uUSB state change interrupt */
		rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
					TYPEC_WATER_DETECTION_INT_EN_BIT |
					MICRO_USB_STATE_CHANGE_INT_EN_BIT,
					TYPEC_WATER_DETECTION_INT_EN_BIT |
					MICRO_USB_STATE_CHANGE_INT_EN_BIT);
		if (rc < 0) {
			smblib_err(chg, "Couldn't enable moisture detection and uUSB state change interrupt rc=%d\n",
				rc);
			return rc;
		}

		/* Disable periodic monitoring of CC_ID pin */
		rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0);
		if (rc < 0) {
			smblib_err(chg, "Couldn't disable 1 percent CC_ID duty cycle rc=%d\n",
				rc);
			return rc;
		}

		/* Enable uUSB factory mode detection */
		rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
					EN_MICRO_USB_FACTORY_MODE_BIT,
					EN_MICRO_USB_FACTORY_MODE_BIT);
		if (rc < 0) {
			smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n",
				rc);
			return rc;
		}
	}

	smblib_dbg(chg, PR_MISC, "Moisture protection %s\n",
			chg->moisture_present ? "enabled" : "disabled");
	return rc;
}

/*********************
/*********************
 * VOTABLE CALLBACKS *
 * VOTABLE CALLBACKS *
 *********************/
 *********************/
@@ -4771,11 +4865,27 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
	smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);


	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
	if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
		if (chg->uusb_moisture_protection_enabled) {
			/*
			 * Adding pm_stay_awake as because pm_relax is called
			 * on exit path from the work routine.
			 */
			pm_stay_awake(chg->dev);
			schedule_work(&chg->moisture_protection_work);
		}

		cancel_delayed_work_sync(&chg->uusb_otg_work);
		cancel_delayed_work_sync(&chg->uusb_otg_work);
		/*
		 * Skip OTG enablement if RID interrupt triggers with moisture
		 * protection still enabled.
		 */
		if (!chg->moisture_present) {
			vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
			vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0);
			smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
			smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n");
			schedule_delayed_work(&chg->uusb_otg_work,
			schedule_delayed_work(&chg->uusb_otg_work,
				msecs_to_jiffies(chg->otg_delay_ms));
				msecs_to_jiffies(chg->otg_delay_ms));
		}

		goto out;
		goto out;
	}
	}


@@ -5323,6 +5433,96 @@ static void smblib_thermal_regulation_work(struct work_struct *work)
					rc);
					rc);
}
}


#define MOISTURE_PROTECTION_CHECK_DELAY_MS 300000		/* 5 mins */
static void smblib_moisture_protection_work(struct work_struct *work)
{
	struct smb_charger *chg = container_of(work, struct smb_charger,
						moisture_protection_work);
	int rc;
	bool usb_plugged_in;
	u8 stat;

	/*
	 * Disable 1% duty cycle on CC_ID pin and enable uUSB factory mode
	 * detection to track any change on RID, as interrupts are disable.
	 */
	rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0);
	if (rc < 0) {
		smblib_err(chg, "Couldn't disable periodic monitoring of CC_ID rc=%d\n",
			rc);
		goto out;
	}

	rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
					EN_MICRO_USB_FACTORY_MODE_BIT,
					EN_MICRO_USB_FACTORY_MODE_BIT);
	if (rc < 0) {
		smblib_err(chg, "Couldn't enable uUSB factory mode detection rc=%d\n",
			rc);
		goto out;
	}

	/*
	 * Add a delay of 100ms to allow change in rid to reflect on
	 * status registers.
	 */
	msleep(100);

	rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc);
		goto out;
	}
	usb_plugged_in = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT);

	/* Check uUSB status for moisture presence */
	rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat);
	if (rc < 0) {
		smblib_err(chg, "Couldn't read TYPE_C_U_USB_STATUS_REG rc=%d\n",
				rc);
		goto out;
	}

	/*
	 * Factory mode detection happens in case of USB plugged-in by using
	 * a different current source of 2uA which can hamper moisture
	 * detection. Since factory mode is not supported in kernel, factory
	 * mode detection can be considered as equivalent to presence of
	 * moisture.
	 */
	if (stat == U_USB_STATUS_WATER_PRESENT || stat == U_USB_FMB1_BIT ||
			stat == U_USB_FMB2_BIT || (usb_plugged_in &&
			stat == U_USB_FLOAT1_BIT)) {
		smblib_set_moisture_protection(chg, true);
		alarm_start_relative(&chg->moisture_protection_alarm,
			ms_to_ktime(MOISTURE_PROTECTION_CHECK_DELAY_MS));
	} else {
		smblib_set_moisture_protection(chg, false);
		rc = alarm_cancel(&chg->moisture_protection_alarm);
		if (rc < 0)
			smblib_err(chg, "Couldn't cancel moisture protection alarm\n");
	}

out:
	pm_relax(chg->dev);
}

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

	smblib_dbg(chg, PR_MISC, "moisture Protection Alarm Triggered %lld\n",
			ktime_to_ms(now));

	/* Atomic context, cannot use voter */
	pm_stay_awake(chg->dev);
	schedule_work(&chg->moisture_protection_work);

	return ALARMTIMER_NORESTART;
}

static void jeita_update_work(struct work_struct *work)
static void jeita_update_work(struct work_struct *work)
{
{
	struct smb_charger *chg = container_of(work, struct smb_charger,
	struct smb_charger *chg = container_of(work, struct smb_charger,
@@ -5711,6 +5911,20 @@ int smblib_init(struct smb_charger *chg)
	INIT_DELAYED_WORK(&chg->lpd_detach_work, smblib_lpd_detach_work);
	INIT_DELAYED_WORK(&chg->lpd_detach_work, smblib_lpd_detach_work);
	INIT_DELAYED_WORK(&chg->thermal_regulation_work,
	INIT_DELAYED_WORK(&chg->thermal_regulation_work,
					smblib_thermal_regulation_work);
					smblib_thermal_regulation_work);

	if (chg->uusb_moisture_protection_enabled) {
		INIT_WORK(&chg->moisture_protection_work,
					smblib_moisture_protection_work);

		if (alarmtimer_get_rtcdev()) {
			alarm_init(&chg->moisture_protection_alarm,
				ALARM_BOOTTIME, moisture_protection_alarm_cb);
		} else {
			smblib_err(chg, "Failed to initialize moisture protection alarm\n");
			return -ENODEV;
		}
	}

	chg->fake_capacity = -EINVAL;
	chg->fake_capacity = -EINVAL;
	chg->fake_input_current_limited = -EINVAL;
	chg->fake_input_current_limited = -EINVAL;
	chg->fake_batt_status = -EINVAL;
	chg->fake_batt_status = -EINVAL;
@@ -5803,6 +6017,10 @@ int smblib_deinit(struct smb_charger *chg)
{
{
	switch (chg->mode) {
	switch (chg->mode) {
	case PARALLEL_MASTER:
	case PARALLEL_MASTER:
		if (chg->uusb_moisture_protection_enabled) {
			alarm_cancel(&chg->moisture_protection_alarm);
			cancel_work_sync(&chg->moisture_protection_work);
		}
		cancel_work_sync(&chg->bms_update_work);
		cancel_work_sync(&chg->bms_update_work);
		cancel_work_sync(&chg->jeita_update_work);
		cancel_work_sync(&chg->jeita_update_work);
		cancel_work_sync(&chg->pl_update_work);
		cancel_work_sync(&chg->pl_update_work);
+5 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,7 @@ enum print_reason {
#define FCC_STEPPER_VOTER		"FCC_STEPPER_VOTER"
#define FCC_STEPPER_VOTER		"FCC_STEPPER_VOTER"
#define SW_THERM_REGULATION_VOTER	"SW_THERM_REGULATION_VOTER"
#define SW_THERM_REGULATION_VOTER	"SW_THERM_REGULATION_VOTER"
#define JEITA_ARB_VOTER			"JEITA_ARB_VOTER"
#define JEITA_ARB_VOTER			"JEITA_ARB_VOTER"
#define MOISTURE_VOTER			"MOISTURE_VOTER"


#define BOOST_BACK_STORM_COUNT	3
#define BOOST_BACK_STORM_COUNT	3
#define WEAK_CHG_STORM_COUNT	8
#define WEAK_CHG_STORM_COUNT	8
@@ -378,6 +379,7 @@ struct smb_charger {
	struct work_struct	bms_update_work;
	struct work_struct	bms_update_work;
	struct work_struct	pl_update_work;
	struct work_struct	pl_update_work;
	struct work_struct	jeita_update_work;
	struct work_struct	jeita_update_work;
	struct work_struct	moisture_protection_work;
	struct delayed_work	ps_change_timeout_work;
	struct delayed_work	ps_change_timeout_work;
	struct delayed_work	clear_hdc_work;
	struct delayed_work	clear_hdc_work;
	struct delayed_work	icl_change_work;
	struct delayed_work	icl_change_work;
@@ -389,6 +391,7 @@ struct smb_charger {
	struct delayed_work	thermal_regulation_work;
	struct delayed_work	thermal_regulation_work;


	struct alarm		lpd_recheck_timer;
	struct alarm		lpd_recheck_timer;
	struct alarm		moisture_protection_alarm;


	/* secondary charger config */
	/* secondary charger config */
	bool			sec_pl_present;
	bool			sec_pl_present;
@@ -455,6 +458,8 @@ struct smb_charger {
	u32			jeita_soft_hys_thlds[2];
	u32			jeita_soft_hys_thlds[2];
	int			jeita_soft_fcc[2];
	int			jeita_soft_fcc[2];
	int			jeita_soft_fv[2];
	int			jeita_soft_fv[2];
	bool			moisture_present;
	bool			uusb_moisture_protection_enabled;


	/* workaround flag */
	/* workaround flag */
	u32			wa_flags;
	u32			wa_flags;
+11 −0
Original line number Original line Diff line number Diff line
@@ -137,6 +137,7 @@ enum {
#define USBIN_SUSPEND_STS_BIT			BIT(6)
#define USBIN_SUSPEND_STS_BIT			BIT(6)
#define USE_USBIN_BIT				BIT(4)
#define USE_USBIN_BIT				BIT(4)
#define USE_DCIN_BIT				BIT(3)
#define USE_DCIN_BIT				BIT(3)
#define POWER_PATH_MASK				GENMASK(2, 1)
#define VALID_INPUT_POWER_SOURCE_STS_BIT	BIT(0)
#define VALID_INPUT_POWER_SOURCE_STS_BIT	BIT(0)


#define DCDC_CMD_OTG_REG			(DCDC_BASE + 0x40)
#define DCDC_CMD_OTG_REG			(DCDC_BASE + 0x40)
@@ -341,6 +342,10 @@ enum {
#define TYPEC_U_USB_STATUS_REG			(TYPEC_BASE + 0x0F)
#define TYPEC_U_USB_STATUS_REG			(TYPEC_BASE + 0x0F)
#define U_USB_GROUND_NOVBUS_BIT			BIT(6)
#define U_USB_GROUND_NOVBUS_BIT			BIT(6)
#define U_USB_GROUND_BIT			BIT(4)
#define U_USB_GROUND_BIT			BIT(4)
#define U_USB_FMB1_BIT				BIT(3)
#define U_USB_FLOAT1_BIT			BIT(2)
#define U_USB_FMB2_BIT				BIT(1)
#define U_USB_FLOAT2_BIT			BIT(0)


#define TYPE_C_MODE_CFG_REG			(TYPEC_BASE + 0x44)
#define TYPE_C_MODE_CFG_REG			(TYPEC_BASE + 0x44)
#define TYPEC_TRY_MODE_MASK			GENMASK(4, 3)
#define TYPEC_TRY_MODE_MASK			GENMASK(4, 3)
@@ -406,8 +411,14 @@ enum {
#define SEL_SBU2_ISRC_VAL			0x01
#define SEL_SBU2_ISRC_VAL			0x01


#define TYPEC_U_USB_CFG_REG			(TYPEC_BASE + 0x70)
#define TYPEC_U_USB_CFG_REG			(TYPEC_BASE + 0x70)
#define EN_MICRO_USB_FACTORY_MODE_BIT		BIT(1)
#define EN_MICRO_USB_MODE_BIT			BIT(0)
#define EN_MICRO_USB_MODE_BIT			BIT(0)


#define TYPEC_U_USB_WATER_PROTECTION_CFG_REG	(TYPEC_BASE + 0x73)
#define EN_MICRO_USB_WATER_PROTECTION_BIT	BIT(4)
#define MICRO_USB_DETECTION_ON_TIME_CFG_MASK	GENMASK(3, 2)
#define MICRO_USB_DETECTION_PERIOD_CFG_MASK	GENMASK(1, 0)

#define TYPEC_MICRO_USB_MODE_REG		(TYPEC_BASE + 0x73)
#define TYPEC_MICRO_USB_MODE_REG		(TYPEC_BASE + 0x73)
#define MICRO_USB_MODE_ONLY_BIT			BIT(0)
#define MICRO_USB_MODE_ONLY_BIT			BIT(0)
/********************************
/********************************