Skip to content

Commit

Permalink
ASoC: adau: Factor out shared PLL configuration code
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Lars-Peter Clausen authored and Mark Brown committed Jun 9, 2016
1 parent 1a695a9 commit 0eadaa9
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 62 deletions.
5 changes: 5 additions & 0 deletions sound/soc/codecs/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/codecs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
61 changes: 61 additions & 0 deletions sound/soc/codecs/adau-utils.c
Original file line number Diff line number Diff line change
@@ -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");
7 changes: 7 additions & 0 deletions sound/soc/codecs/adau-utils.h
Original file line number Diff line number Diff line change
@@ -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
38 changes: 10 additions & 28 deletions sound/soc/codecs/adau1373.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <sound/adau1373.h>

#include "adau1373.h"
#include "adau-utils.h"

struct adau1373_dai {
unsigned int clk_src;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down
38 changes: 4 additions & 34 deletions sound/soc/codecs/adau17x1.c
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 0eadaa9

Please sign in to comment.