ASoC: cs42l42: Set clock source for both ways of stream
authorLucas Tanure <tanureal@opensource.cirrus.com>
Sat, 6 Mar 2021 18:55:47 +0000 (18:55 +0000)
committerMark Brown <broonie@kernel.org>
Wed, 10 Mar 2021 13:14:25 +0000 (13:14 +0000)
Move the enable/disable of clocks to cs42l42_mute_stream so the record
path also get clocks.

Signed-off-by: Lucas Tanure <tanureal@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20210306185553.62053-10-tanureal@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/cs42l42.c
sound/soc/codecs/cs42l42.h

index 0b5c8e4..2dca55d 100644 (file)
@@ -784,52 +784,63 @@ static int cs42l42_set_sysclk(struct snd_soc_dai *dai,
        return 0;
 }
 
-static int cs42l42_mute(struct snd_soc_dai *dai, int mute, int direction)
+static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
 {
        struct snd_soc_component *component = dai->component;
+       struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
        unsigned int regval;
        u8 fullScaleVol;
 
        if (mute) {
-               /* Mark SCLK as not present to turn on the internal
-                * oscillator.
-                */
-               snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
-                                               CS42L42_SCLK_PRESENT_MASK, 0);
-
-               snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
-                               CS42L42_PLL_START_MASK,
-                               0 << CS42L42_PLL_START_SHIFT);
-
                /* Mute the headphone */
-               snd_soc_component_update_bits(component, CS42L42_HP_CTL,
-                               CS42L42_HP_ANA_AMUTE_MASK |
-                               CS42L42_HP_ANA_BMUTE_MASK,
-                               CS42L42_HP_ANA_AMUTE_MASK |
-                               CS42L42_HP_ANA_BMUTE_MASK);
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       snd_soc_component_update_bits(component, CS42L42_HP_CTL,
+                                                     CS42L42_HP_ANA_AMUTE_MASK |
+                                                     CS42L42_HP_ANA_BMUTE_MASK,
+                                                     CS42L42_HP_ANA_AMUTE_MASK |
+                                                     CS42L42_HP_ANA_BMUTE_MASK);
+
+               cs42l42->stream_use &= ~(1 << stream);
+               if(!cs42l42->stream_use) {
+                       /*
+                        * Switch to the internal oscillator.
+                        * SCLK must remain running until after this clock switch.
+                        * Without a source of clock the I2C bus doesn't work.
+                        */
+                       snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
+                                                     CS42L42_SCLK_PRESENT_MASK, 0);
+                       snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
+                                                     CS42L42_PLL_START_MASK, 0);
+               }
        } else {
-               snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
-                               CS42L42_PLL_START_MASK,
-                               1 << CS42L42_PLL_START_SHIFT);
-               /* Read the headphone load */
-               regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT);
-               if (((regval & CS42L42_RLA_STAT_MASK) >>
-                       CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) {
-                       fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
-               } else {
-                       fullScaleVol = 0;
+               if (!cs42l42->stream_use) {
+                       /* SCLK must be running before codec unmute */
+                       snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
+                                                     CS42L42_PLL_START_MASK, 1);
+
+                       /* Mark SCLK as present, turn off internal oscillator */
+                       snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
+                                                     CS42L42_SCLK_PRESENT_MASK,
+                                                     CS42L42_SCLK_PRESENT_MASK);
                }
+               cs42l42->stream_use |= 1 << stream;
+
+               if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       /* Read the headphone load */
+                       regval = snd_soc_component_read(component, CS42L42_LOAD_DET_RCSTAT);
+                       if (((regval & CS42L42_RLA_STAT_MASK) >> CS42L42_RLA_STAT_SHIFT) ==
+                           CS42L42_RLA_STAT_15_OHM) {
+                               fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK;
+                       } else {
+                               fullScaleVol = 0;
+                       }
 
-               /* Un-mute the headphone, set the full scale volume flag */
-               snd_soc_component_update_bits(component, CS42L42_HP_CTL,
-                               CS42L42_HP_ANA_AMUTE_MASK |
-                               CS42L42_HP_ANA_BMUTE_MASK |
-                               CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
-
-               /* Mark SCLK as present, turn off internal oscillator */
-               snd_soc_component_update_bits(component, CS42L42_OSC_SWITCH,
-                               CS42L42_SCLK_PRESENT_MASK,
-                               CS42L42_SCLK_PRESENT_MASK);
+                       /* Un-mute the headphone, set the full scale volume flag */
+                       snd_soc_component_update_bits(component, CS42L42_HP_CTL,
+                                                     CS42L42_HP_ANA_AMUTE_MASK |
+                                                     CS42L42_HP_ANA_BMUTE_MASK |
+                                                     CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol);
+               }
        }
 
        return 0;
@@ -844,8 +855,7 @@ static const struct snd_soc_dai_ops cs42l42_ops = {
        .hw_params      = cs42l42_pcm_hw_params,
        .set_fmt        = cs42l42_set_dai_fmt,
        .set_sysclk     = cs42l42_set_sysclk,
-       .mute_stream    = cs42l42_mute,
-       .no_capture_mute = 1,
+       .mute_stream    = cs42l42_mute_stream,
 };
 
 static struct snd_soc_dai_driver cs42l42_dai = {
index 4b448c1..3dcbfeb 100644 (file)
@@ -768,6 +768,7 @@ struct  cs42l42_private {
        u8 bias_thresholds[CS42L42_NUM_BIASES];
        u8 hs_bias_ramp_rate;
        u8 hs_bias_ramp_time;
+       u8 stream_use;
 };
 
 #endif /* __CS42L42_H__ */