ALSA: ASoC: cs4271: add optional soft reset workaround
authorDaniel Mack <zonque@gmail.com>
Mon, 10 Dec 2012 09:30:04 +0000 (10:30 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 24 Dec 2012 15:53:28 +0000 (15:53 +0000)
The CS4271 requires its LRCLK and MCLK to be stable before its RESET
line is de-asserted. That also means that clocks cannot be changed
without putting the chip back into hardware reset, which also requires
a complete re-initialization of all registers.

One (undocumented) workaround is to assert and de-assert the PDN bit
in the MODE2 register.

This patch adds a new flag to both the DT bindings as well as to the
platform data to enable that workaround.

Signed-off-by: Daniel Mack <zonque@gmail.com>
Acked-by: Alexander Sverdlin <subaparts@yandex.ru>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Documentation/devicetree/bindings/sound/cs4271.txt
include/sound/cs4271.h
sound/soc/codecs/cs4271.c

index a850fb9..e2cd1d7 100644 (file)
@@ -20,6 +20,18 @@ Optional properties:
                !RESET pin
  - cirrus,amuteb-eq-bmutec:    When given, the Codec's AMUTEB=BMUTEC flag
                                is enabled.
+ - cirrus,enable-soft-reset:
+       The CS4271 requires its LRCLK and MCLK to be stable before its RESET
+       line is de-asserted. That also means that clocks cannot be changed
+       without putting the chip back into hardware reset, which also requires
+       a complete re-initialization of all registers.
+
+       One (undocumented) workaround is to assert and de-assert the PDN bit
+       in the MODE2 register. This workaround can be enabled with this DT
+       property.
+
+       Note that this is not needed in case the clocks are stable
+       throughout the entire runtime of the codec.
 
 Examples:
 
index dd8c48d..70f4535 100644 (file)
 struct cs4271_platform_data {
        int gpio_nreset;        /* GPIO driving Reset pin, if any */
        bool amutec_eq_bmutec;  /* flag to enable AMUTEC=BMUTEC */
+
+       /*
+        * The CS4271 requires its LRCLK and MCLK to be stable before its RESET
+        * line is de-asserted. That also means that clocks cannot be changed
+        * without putting the chip back into hardware reset, which also requires
+        * a complete re-initialization of all registers.
+        *
+        * One (undocumented) workaround is to assert and de-assert the PDN bit
+        * in the MODE2 register. This workaround can be enabled with the
+        * following flag.
+        *
+        * Note that this is not needed in case the clocks are stable
+        * throughout the entire runtime of the codec.
+        */
+       bool enable_soft_reset;
 };
 
 #endif /* __CS4271_H */
index ac8742a..2415a41 100644 (file)
@@ -167,6 +167,8 @@ struct cs4271_private {
        int                             gpio_nreset;
        /* GPIO that disable serial bus, if any */
        int                             gpio_disable;
+       /* enable soft reset workaround */
+       bool                            enable_soft_reset;
 };
 
 /*
@@ -325,6 +327,33 @@ static int cs4271_hw_params(struct snd_pcm_substream *substream,
        int i, ret;
        unsigned int ratio, val;
 
+       if (cs4271->enable_soft_reset) {
+               /*
+                * Put the codec in soft reset and back again in case it's not
+                * currently streaming data. This way of bringing the codec in
+                * sync to the current clocks is not explicitly documented in
+                * the data sheet, but it seems to work fine, and in contrast
+                * to a read hardware reset, we don't have to sync back all
+                * registers every time.
+                */
+
+               if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
+                    !dai->capture_active) ||
+                   (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
+                    !dai->playback_active)) {
+                       ret = snd_soc_update_bits(codec, CS4271_MODE2,
+                                                 CS4271_MODE2_PDN,
+                                                 CS4271_MODE2_PDN);
+                       if (ret < 0)
+                               return ret;
+
+                       ret = snd_soc_update_bits(codec, CS4271_MODE2,
+                                                 CS4271_MODE2_PDN, 0);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
        cs4271->rate = params_rate(params);
 
        /* Configure DAC */
@@ -484,6 +513,10 @@ static int cs4271_probe(struct snd_soc_codec *codec)
                if (of_get_property(codec->dev->of_node,
                                     "cirrus,amutec-eq-bmutec", NULL))
                        amutec_eq_bmutec = true;
+
+               if (of_get_property(codec->dev->of_node,
+                                    "cirrus,enable-soft-reset", NULL))
+                       cs4271->enable_soft_reset = true;
        }
 #endif
 
@@ -492,6 +525,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
                        gpio_nreset = cs4271plat->gpio_nreset;
 
                amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec;
+               cs4271->enable_soft_reset = cs4271plat->enable_soft_reset;
        }
 
        if (gpio_nreset >= 0)