ASoC: codecs: ad193x: Add support to disable on-chip PLL
authorCodrin Ciubotariu <codrin.ciubotariu@microchip.com>
Mon, 18 Feb 2019 16:10:36 +0000 (16:10 +0000)
committerMark Brown <broonie@kernel.org>
Mon, 18 Feb 2019 17:41:42 +0000 (17:41 +0000)
The on-chip PLL can be disabled if on the MCLKI pin we have an external
clock at 512 x fs. This clock can be used as direct internal clock for
ADCs or DACs.
To support this, we add an extra clock id that can be configured
using the set_sysclk() callback.

Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/ad193x.c
sound/soc/codecs/ad193x.h

index f8cf182518a319f3c217cdeb6b5fa25693291aa7..96d7cb2e4a561f031e3403f0dfc343e011761c9f 100644 (file)
@@ -100,6 +100,15 @@ static const struct snd_soc_dapm_widget ad193x_adc_widgets[] = {
        SND_SOC_DAPM_INPUT("ADC2IN"),
 };
 
+static int ad193x_check_pll(struct snd_soc_dapm_widget *source,
+                           struct snd_soc_dapm_widget *sink)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(source->dapm);
+       struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
+
+       return !!ad193x->sysclk;
+}
+
 static const struct snd_soc_dapm_route audio_paths[] = {
        { "DAC", NULL, "SYSCLK" },
        { "DAC Output", NULL, "DAC" },
@@ -108,7 +117,7 @@ static const struct snd_soc_dapm_route audio_paths[] = {
        { "DAC2OUT", NULL, "DAC Output" },
        { "DAC3OUT", NULL, "DAC Output" },
        { "DAC4OUT", NULL, "DAC Output" },
-       { "SYSCLK", NULL, "PLL_PWR" },
+       { "SYSCLK", NULL, "PLL_PWR", &ad193x_check_pll },
 };
 
 static const struct snd_soc_dapm_route ad193x_adc_audio_paths[] = {
@@ -276,7 +285,22 @@ static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                int clk_id, unsigned int freq, int dir)
 {
        struct snd_soc_component *component = codec_dai->component;
+       struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component);
        struct ad193x_priv *ad193x = snd_soc_component_get_drvdata(component);
+
+       if (clk_id == AD193X_SYSCLK_MCLK) {
+               /* MCLK must be 512 x fs */
+               if (dir == SND_SOC_CLOCK_OUT || freq != 24576000)
+                       return -EINVAL;
+
+               regmap_update_bits(ad193x->regmap, AD193X_PLL_CLK_CTRL1,
+                                  AD193X_PLL_SRC_MASK,
+                                  AD193X_PLL_DAC_SRC_MCLK |
+                                  AD193X_PLL_CLK_SRC_MCLK);
+
+               snd_soc_dapm_sync(dapm);
+               return 0;
+       }
        switch (freq) {
        case 12288000:
        case 18432000:
index 8b1e65f928d2ad92cabb6f6773af487c1b94a1bc..27d6afbd7dfbfdc7874427c8edc69f673c35d017 100644 (file)
@@ -31,6 +31,11 @@ int ad193x_probe(struct device *dev, struct regmap *regmap,
 #define AD193X_PLL_INPUT_512    (2 << 1)
 #define AD193X_PLL_INPUT_768    (3 << 1)
 #define AD193X_PLL_CLK_CTRL1    0x01
+#define AD193X_PLL_SRC_MASK    0x03
+#define AD193X_PLL_DAC_SRC_PLL  0
+#define AD193X_PLL_DAC_SRC_MCLK 1
+#define AD193X_PLL_CLK_SRC_PLL  (0 << 1)
+#define AD193X_PLL_CLK_SRC_MCLK        (1 << 1)
 #define AD193X_DAC_CTRL0        0x02
 #define AD193X_DAC_POWERDOWN           0x01
 #define AD193X_DAC_SERFMT_MASK         0xC0
@@ -96,4 +101,7 @@ int ad193x_probe(struct device *dev, struct regmap *regmap,
 
 #define AD193X_NUM_REGS          17
 
+#define AD193X_SYSCLK_PLL      0
+#define AD193X_SYSCLK_MCLK     1
+
 #endif