Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0eadaa9c authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Mark Brown
Browse files

ASoC: adau: Factor out shared PLL configuration code



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: default avatarLars-Peter Clausen <lars@metafoo.de>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 1a695a90
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -269,8 +269,12 @@ config SND_SOC_AD1980
config SND_SOC_AD73311
config SND_SOC_AD73311
	tristate
	tristate


config SND_SOC_ADAU_UTILS
	tristate

config SND_SOC_ADAU1373
config SND_SOC_ADAU1373
	tristate
	tristate
	select SND_SOC_ADAU_UTILS


config SND_SOC_ADAU1701
config SND_SOC_ADAU1701
	tristate "Analog Devices ADAU1701 CODEC"
	tristate "Analog Devices ADAU1701 CODEC"
@@ -280,6 +284,7 @@ config SND_SOC_ADAU1701
config SND_SOC_ADAU17X1
config SND_SOC_ADAU17X1
	tristate
	tristate
	select SND_SOC_SIGMADSP_REGMAP
	select SND_SOC_SIGMADSP_REGMAP
	select SND_SOC_ADAU_UTILS


config SND_SOC_ADAU1761
config SND_SOC_ADAU1761
	tristate
	tristate
+2 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
snd-soc-ad193x-i2c-objs := ad193x-i2c.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
snd-soc-ad73311-objs := ad73311.o
snd-soc-adau-utils-objs := adau-utils.o
snd-soc-adau1373-objs := adau1373.o
snd-soc-adau1373-objs := adau1373.o
snd-soc-adau1701-objs := adau1701.o
snd-soc-adau1701-objs := adau1701.o
snd-soc-adau17x1-objs := adau17x1.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_AD193X_I2C)	+= snd-soc-ad193x-i2c.o
obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD1980)	+= snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.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_ADAU1373)	+= snd-soc-adau1373.o
obj-$(CONFIG_SND_SOC_ADAU1701)		+= snd-soc-adau1701.o
obj-$(CONFIG_SND_SOC_ADAU1701)		+= snd-soc-adau1701.o
obj-$(CONFIG_SND_SOC_ADAU17X1)		+= snd-soc-adau17x1.o
obj-$(CONFIG_SND_SOC_ADAU17X1)		+= snd-soc-adau17x1.o
+61 −0
Original line number Original line Diff line number Diff line
/*
 * 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 −0
Original line number Original line Diff line number Diff line
#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
+10 −28
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@
#include <sound/adau1373.h>
#include <sound/adau1373.h>


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


struct adau1373_dai {
struct adau1373_dai {
	unsigned int clk_src;
	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);
	struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
	unsigned int dpll_div = 0;
	unsigned int dpll_div = 0;
	unsigned int x, r, n, m, i, j, mode;
	uint8_t pll_regs[5];
	int ret;


	switch (pll_id) {
	switch (pll_id) {
	case ADAU1373_PLL1:
	case ADAU1373_PLL1:
@@ -1295,27 +1297,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id,
		dpll_div++;
		dpll_div++;
	}
	}


	if (freq_out % freq_in != 0) {
	ret = adau_calc_pll_cfg(freq_in, freq_out, pll_regs);
		/* fout = fin * (r + (n/m)) / x */
	if (ret)
		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)
		return -EINVAL;
		return -EINVAL;


	if (dpll_div) {
	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),
	regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id),
		(source << 4) | dpll_div);
		(source << 4) | dpll_div);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), pll_regs[0]);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), pll_regs[1]);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), pll_regs[2]);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), pll_regs[3]);
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id),
	regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), pll_regs[4]);
		(r << 3) | (x << 1) | mode);


	/* Set sysclk to pll_rate / 4 */
	/* Set sysclk to pll_rate / 4 */
	regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
	regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09);
Loading