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

Commit 559d4878 authored by Jack Pham's avatar Jack Pham
Browse files

fsa4480: Avoid updating settings if unchanged



During audio subsystem restart, the audio driver will unregister
its notifier on shutdown and re-register when subsystem is up again.
If a regular USB device, and not a Type-C analog audio device, is
currently connected, we should not re-write the register settings
over I2C to the FSA4480 IC as that will make the D+/D- pins to
be momentarily switched off an on, which causes the USB controller
to detect a momentary disconnect and re-connect of the attached
peripheral.

Fix this by first reading the switch control and enable registers,
and if being updated with the same values, don't re-write them to
avoid unnecessarily resetting D+/D- or SBU1/2.

Change-Id: I9d4e092e9782ca64caf0982958b3e5d05744aa92
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent 4cf5de75
Loading
Loading
Loading
Loading
+15 −28
Original line number Diff line number Diff line
@@ -69,11 +69,21 @@ static const struct fsa4480_reg_val fsa_reg_i2c_defaults[] = {
static void fsa4480_usbc_update_settings(struct fsa4480_priv *fsa_priv,
		u32 switch_control, u32 switch_enable)
{
	u32 prev_control, prev_enable;

	if (!fsa_priv->regmap) {
		dev_err(fsa_priv->dev, "%s: regmap invalid\n", __func__);
		return;
	}

	regmap_read(fsa_priv->regmap, FSA4480_SWITCH_CONTROL, &prev_control);
	regmap_read(fsa_priv->regmap, FSA4480_SWITCH_SETTINGS, &prev_enable);

	if (prev_control == switch_control && prev_enable == switch_enable) {
		dev_dbg(fsa_priv->dev, "%s: settings unchanged\n", __func__);
		return;
	}

	regmap_write(fsa_priv->regmap, FSA4480_SWITCH_SETTINGS, 0x80);
	regmap_write(fsa_priv->regmap, FSA4480_SWITCH_CONTROL, switch_control);
	/* FSA4480 chip hardware requirement */
@@ -181,8 +191,6 @@ static int fsa4480_usbc_analog_setup_switches_psupply(

	dev_dbg(dev, "%s: setting GPIOs active = %d rcvd intval 0x%X\n",
		__func__, mode.intval != TYPEC_ACCESSORY_NONE, mode.intval);
	if (atomic_read(&(fsa_priv->usbc_mode)) == mode.intval)
		goto done; /* filter notifications received before */
	atomic_set(&(fsa_priv->usbc_mode), mode.intval);

	switch (mode.intval) {
@@ -321,8 +329,6 @@ int fsa4480_unreg_notifier(struct notifier_block *nb,
	int rc = 0;
	struct i2c_client *client = of_find_i2c_device_by_node(node);
	struct fsa4480_priv *fsa_priv;
	struct device *dev;
	union power_supply_propval mode;

	if (!client)
		return -EINVAL;
@@ -330,33 +336,14 @@ int fsa4480_unreg_notifier(struct notifier_block *nb,
	fsa_priv = (struct fsa4480_priv *)i2c_get_clientdata(client);
	if (!fsa_priv)
		return -EINVAL;
	if (fsa_priv->use_powersupply) {
		dev = fsa_priv->dev;
		if (!dev)
			return -EINVAL;

	mutex_lock(&fsa_priv->notification_lock);
		/* get latest mode within locked context */

		rc = iio_read_channel_processed(fsa_priv->iio_ch, &mode.intval);

		if (rc) {
			dev_dbg(dev, "%s: Unable to read USB TYPEC_MODE: %d\n",
				__func__, rc);
			mutex_unlock(&fsa_priv->notification_lock);
			return rc;
		}
		/* Do not reset switch settings for usb digital hs */
		if (mode.intval == TYPEC_ACCESSORY_AUDIO)
	fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
	rc = blocking_notifier_chain_unregister
				(&fsa_priv->fsa4480_notifier, nb);
	mutex_unlock(&fsa_priv->notification_lock);
	} else {
		fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98);
		rc = blocking_notifier_chain_unregister
				(&fsa_priv->fsa4480_notifier, nb);
	}

	return rc;
}
EXPORT_SYMBOL(fsa4480_unreg_notifier);