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

Commit af93d7c9 authored by Xiaolei Wang's avatar Xiaolei Wang Committed by Greg Kroah-Hartman
Browse files

ASoC: wm8962: Add an event handler for TEMP_HP and TEMP_SPK



[ Upstream commit ee1aa2ae3eaa96e70229fa61deee87ef4528ffdf ]

In wm8962 driver, the WM8962_ADDITIONAL_CONTROL_4 is used as a volatile
register, but this register mixes a bunch of volatile status bits and a
bunch of non-volatile control bits. The dapm widgets TEMP_HP and
TEMP_SPK leverages the control bits in this register. After the wm8962
probe, the regmap will bet set to cache only mode, then a read error
like below would be triggered when trying to read the initial power
state of the dapm widgets TEMP_HP and TEMP_SPK.
  wm8962 0-001a: ASoC: error at soc_component_read_no_lock
  on wm8962.0-001a: -16

In order to fix this issue, we add event handler to actually power
up/down these widgets. With this change, we also need to explicitly
power off these widgets in the wm8962 probe since they are enabled
by default.

Signed-off-by: default avatarXiaolei Wang <xiaolei.wang@windriver.com>
Tested-by: default avatarAdam Ford <aford173@gmail.com>
Acked-by: default avatarCharles Keepax <ckeepax@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20221010092014.2229246-1-xiaolei.wang@windriver.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent a3b07bb0
Loading
Loading
Loading
Loading
+52 −2
Original line number Diff line number Diff line
@@ -1840,6 +1840,49 @@ SOC_SINGLE_TLV("SPKOUTR Mixer DACR Volume", WM8962_SPEAKER_MIXER_5,
	       4, 1, 0, inmix_tlv),
};

static int tp_event(struct snd_soc_dapm_widget *w,
		    struct snd_kcontrol *kcontrol, int event)
{
	int ret, reg, val, mask;
	struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);

	ret = pm_runtime_resume_and_get(component->dev);
	if (ret < 0) {
		dev_err(component->dev, "Failed to resume device: %d\n", ret);
		return ret;
	}

	reg = WM8962_ADDITIONAL_CONTROL_4;

	if (!strcmp(w->name, "TEMP_HP")) {
		mask = WM8962_TEMP_ENA_HP_MASK;
		val = WM8962_TEMP_ENA_HP;
	} else if (!strcmp(w->name, "TEMP_SPK")) {
		mask = WM8962_TEMP_ENA_SPK_MASK;
		val = WM8962_TEMP_ENA_SPK;
	} else {
		pm_runtime_put(component->dev);
		return -EINVAL;
	}

	switch (event) {
	case SND_SOC_DAPM_POST_PMD:
		val = 0;
		fallthrough;
	case SND_SOC_DAPM_POST_PMU:
		ret = snd_soc_component_update_bits(component, reg, mask, val);
		break;
	default:
		WARN(1, "Invalid event %d\n", event);
		pm_runtime_put(component->dev);
		return -EINVAL;
	}

	pm_runtime_put(component->dev);

	return 0;
}

static int cp_event(struct snd_soc_dapm_widget *w,
		    struct snd_kcontrol *kcontrol, int event)
{
@@ -2132,8 +2175,10 @@ SND_SOC_DAPM_SUPPLY("TOCLK", WM8962_ADDITIONAL_CONTROL_1, 0, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DSP2", 1, WM8962_DSP2_POWER_MANAGEMENT,
		      WM8962_DSP2_ENA_SHIFT, 0, dsp2_event,
		      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
SND_SOC_DAPM_SUPPLY("TEMP_HP", WM8962_ADDITIONAL_CONTROL_4, 2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("TEMP_SPK", WM8962_ADDITIONAL_CONTROL_4, 1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("TEMP_HP", SND_SOC_NOPM, 0, 0, tp_event,
		SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("TEMP_SPK", SND_SOC_NOPM, 0, 0, tp_event,
		SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),

SND_SOC_DAPM_MIXER("INPGAL", WM8962_LEFT_INPUT_PGA_CONTROL, 4, 0,
		   inpgal, ARRAY_SIZE(inpgal)),
@@ -3750,6 +3795,11 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
	if (ret < 0)
		goto err_pm_runtime;

	regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
			    WM8962_TEMP_ENA_HP_MASK, 0);
	regmap_update_bits(wm8962->regmap, WM8962_ADDITIONAL_CONTROL_4,
			    WM8962_TEMP_ENA_SPK_MASK, 0);

	regcache_cache_only(wm8962->regmap, true);

	/* The drivers should power up as needed */