ASoC: adau: Factor out shared PLL configuration code
authorLars-Peter Clausen <lars@metafoo.de>
Thu, 9 Jun 2016 17:39:06 +0000 (19:39 +0200)
committerMark Brown <broonie@kernel.org>
Thu, 9 Jun 2016 17:41:41 +0000 (18:41 +0100)
Multiple devices from the ADAU family share the same PLL structure and
configuration register layout. Introduce a new helper module that can be
used to calculated the PLL configuration registers based on a specified
input frequency and the desired output frequency of the PLL.

The ADAU1761/ADAU1781 and ADAU1373 drivers are updated to make use of this
new helper module. But future drivers for additional devices from the ADAU
family are also expected to make use of it.

In anticipation of sharing more infrastructure code between different
devices from the ADAU family the new module is called adau-utils.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/adau-utils.c [new file with mode: 0644]
sound/soc/codecs/adau-utils.h [new file with mode: 0644]
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau17x1.c

index 4d82a58ff6b0b9c43c9f6f892ecbd6ab79e44de8..3e215395a199cc2db5d35ec8347a14cdcf775eb9 100644 (file)
@@ -269,8 +269,12 @@ config SND_SOC_AD1980
 config SND_SOC_AD73311
        tristate
 
+config SND_SOC_ADAU_UTILS
+       tristate
+
 config SND_SOC_ADAU1373
        tristate
+       select SND_SOC_ADAU_UTILS
 
 config SND_SOC_ADAU1701
        tristate "Analog Devices ADAU1701 CODEC"
@@ -280,6 +284,7 @@ config SND_SOC_ADAU1701
 config SND_SOC_ADAU17X1
        tristate
        select SND_SOC_SIGMADSP_REGMAP
+       select SND_SOC_ADAU_UTILS
 
 config SND_SOC_ADAU1761
        tristate
index 0f548fd34ca3fd9e8a1b080cd2d38a480c3c5212..d61957f2618ccc0f83d3eeafa1f346e75f92a8e7 100644 (file)
@@ -7,6 +7,7 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o
 snd-soc-ad193x-i2c-objs := ad193x-i2c.o
 snd-soc-ad1980-objs := ad1980.o
 snd-soc-ad73311-objs := ad73311.o
+snd-soc-adau-utils-objs := adau-utils.o
 snd-soc-adau1373-objs := adau1373.o
 snd-soc-adau1701-objs := adau1701.o
 snd-soc-adau17x1-objs := adau17x1.o
@@ -220,6 +221,7 @@ obj-$(CONFIG_SND_SOC_AD193X_SPI)    += snd-soc-ad193x-spi.o
 obj-$(CONFIG_SND_SOC_AD193X_I2C)       += snd-soc-ad193x-i2c.o
 obj-$(CONFIG_SND_SOC_AD1980)   += snd-soc-ad1980.o
 obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
+obj-$(CONFIG_SND_SOC_ADAU_UTILS)       += snd-soc-adau-utils.o
 obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o
 obj-$(CONFIG_SND_SOC_ADAU1701)         += snd-soc-adau1701.o
 obj-$(CONFIG_SND_SOC_ADAU17X1)         += snd-soc-adau17x1.o
diff --git a/sound/soc/codecs/adau-utils.c b/sound/soc/codecs/adau-utils.c
new file mode 100644 (file)
index 0000000..19d6a6f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Shared helper functions for devices from the ADAU family
+ *
+ * Copyright 2011-2016 Analog Devices Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/gcd.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "adau-utils.h"
+
+int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out,
+       uint8_t regs[5])
+{
+       unsigned int r, n, m, i, j;
+       unsigned int div;
+
+       if (!freq_out) {
+               r = 0;
+               n = 0;
+               m = 0;
+               div = 0;
+       } else {
+               if (freq_out % freq_in != 0) {
+                       div = DIV_ROUND_UP(freq_in, 13500000);
+                       freq_in /= div;
+                       r = freq_out / freq_in;
+                       i = freq_out % freq_in;
+                       j = gcd(i, freq_in);
+                       n = i / j;
+                       m = freq_in / j;
+                       div--;
+               } else {
+                       r = freq_out / freq_in;
+                       n = 0;
+                       m = 0;
+                       div = 0;
+               }
+               if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
+                       return -EINVAL;
+       }
+
+       regs[0] = m >> 8;
+       regs[1] = m & 0xff;
+       regs[2] = n >> 8;
+       regs[3] = n & 0xff;
+       regs[4] = (r << 3) | (div << 1);
+       if (m != 0)
+               regs[4] |= 1; /* Fractional mode */
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(adau_calc_pll_cfg);
+
+MODULE_DESCRIPTION("ASoC ADAU audio CODECs shared helper functions");
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/adau-utils.h b/sound/soc/codecs/adau-utils.h
new file mode 100644 (file)
index 0000000..939b5f3
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef SOUND_SOC_CODECS_ADAU_PLL_H
+#define SOUND_SOC_CODECS_ADAU_PLL_H
+
+int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out,
+       uint8_t regs[5]);
+
+#endif
index fe1353a797b9449e7b8186771c8476b2cf746021..1556b360fa1516b2c5048b980274e72d8540a228 100644 (file)
@@ -23,6 +23,7 @@
 #include <sound/adau1373.h>
 
 #include "adau1373.h"
+#include "adau-utils.h"
 
 struct adau1373_dai {
        unsigned int clk_src;
@@ -1254,7 +1255,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
 {
        struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
        unsigned int dpll_div = 0;
-       unsigned int x, r, n, m, i, j, mode;
+       uint8_t pll_regs[5];
+       int ret;
 
        switch (pll_id) {
        case ADAU1373_PLL1:
@@ -1295,27 +1297,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
                dpll_div++;
        }
 
-       if (freq_out % freq_in != 0) {
-               /* fout = fin * (r + (n/m)) / x */
-               x = DIV_ROUND_UP(freq_in, 13500000);
-               freq_in /= x;
-               r = freq_out / freq_in;
-               i = freq_out % freq_in;
-               j = gcd(i, freq_in);
-               n = i / j;
-               m = freq_in / j;
-               x--;
-               mode = 1;
-       } else {
-               /* fout = fin / r */
-               r = freq_out / freq_in;
-               n = 0;
-               m = 0;
-               x = 0;
-               mode = 0;
-       }
-
-       if (r < 2 || r > 8 || x > 3 || m > 0xffff || n > 0xffff)
+       ret = adau_calc_pll_cfg(freq_in, freq_out, pll_regs);
+       if (ret)
                return -EINVAL;
 
        if (dpll_div) {
@@ -1330,12 +1313,11 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
 
        regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),
                (source << 4) | dpll_div);
-       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
-       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
-       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
-       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
-       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id),
-               (r << 3) | (x << 1) | mode);
+       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), pll_regs[0]);
+       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), pll_regs[1]);
+       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), pll_regs[2]);
+       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), pll_regs[3]);
+       regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), pll_regs[4]);
 
        /* Set sysclk to pll_rate / 4 */
        regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
index fcf05b254ecd5c37a91dbff5a3ccc3de1069e2f0..66a6e061923d7b19b6896e8f4ee35442502281e1 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "sigmadsp.h"
 #include "adau17x1.h"
+#include "adau-utils.h"
 
 static const char * const adau17x1_capture_mixer_boost_text[] = {
        "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3",
@@ -391,45 +392,14 @@ static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id,
 {
        struct snd_soc_codec *codec = dai->codec;
        struct adau *adau = snd_soc_codec_get_drvdata(codec);
-       unsigned int r, n, m, i, j;
-       unsigned int div;
        int ret;
 
        if (freq_in < 8000000 || freq_in > 27000000)
                return -EINVAL;
 
-       if (!freq_out) {
-               r = 0;
-               n = 0;
-               m = 0;
-               div = 0;
-       } else {
-               if (freq_out % freq_in != 0) {
-                       div = DIV_ROUND_UP(freq_in, 13500000);
-                       freq_in /= div;
-                       r = freq_out / freq_in;
-                       i = freq_out % freq_in;
-                       j = gcd(i, freq_in);
-                       n = i / j;
-                       m = freq_in / j;
-                       div--;
-               } else {
-                       r = freq_out / freq_in;
-                       n = 0;
-                       m = 0;
-                       div = 0;
-               }
-               if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2)
-                       return -EINVAL;
-       }
-
-       adau->pll_regs[0] = m >> 8;
-       adau->pll_regs[1] = m & 0xff;
-       adau->pll_regs[2] = n >> 8;
-       adau->pll_regs[3] = n & 0xff;
-       adau->pll_regs[4] = (r << 3) | (div << 1);
-       if (m != 0)
-               adau->pll_regs[4] |= 1; /* Fractional mode */
+       ret = adau_calc_pll_cfg(freq_in, freq_out, adau->pll_regs);
+       if (ret < 0)
+               return ret;
 
        /* The PLL register is 6 bytes long and can only be written at once. */
        ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL,