From 559d48787811b1a4ffedfc7900ad872282a2c142 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Fri, 9 Oct 2020 00:38:28 -0700 Subject: [PATCH] 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: Jack Pham --- drivers/soc/qcom/fsa4480-i2c.c | 43 ++++++++++++---------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/drivers/soc/qcom/fsa4480-i2c.c b/drivers/soc/qcom/fsa4480-i2c.c index 53566abd724c..a0568ab3a0ba 100644 --- a/drivers/soc/qcom/fsa4480-i2c.c +++ b/drivers/soc/qcom/fsa4480-i2c.c @@ -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 */ + mutex_lock(&fsa_priv->notification_lock); - 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 + fsa4480_usbc_update_settings(fsa_priv, 0x18, 0x98); + rc = blocking_notifier_chain_unregister (&fsa_priv->fsa4480_notifier, nb); - } + mutex_unlock(&fsa_priv->notification_lock); + return rc; } EXPORT_SYMBOL(fsa4480_unreg_notifier);