All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting
@ 2019-03-19  3:37 Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 01/13] ASoC: tlv320aic32x4: Break out clock setting into separate function Annaliese McDermond
                   ` (12 more replies)
  0 siblings, 13 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

The current tlv320aic32x4 code sets the various clock parameters by
looking in a static table in the kernel.  This works well enough,
but it has a few disadvantages.

1)  If the master clock doesn't match one of the precalculated values
    the driver cannot work.  This could be because the designer
    decided to use a different crystal, or because the clock comes
    from a PLL that can't quite achieve the proper frequency
    exactly.

2)  The driver only supports certain pre-calculated sample rates.
    The actual hardware can support many more.  These changes
    enable those rates.  Additionally, certain sample rates at
    certain clock rates were previously unavailable as
    combinations.

This patch dynamically calculates the various PLL and divider
values to find something that works.

Additionally, to enable much of this, the clock tree is
modeled as a part of the Common Clock Framework.  This allows
for easier debugigng as you can use the standard tools such as
/sys/kernel/debug/clk/clk_summary.  It also simplifies enabling
the entirety of the clock tree needed, and makes sure unused
clocks become disabled.

These patches have been tested and are working on a Raspberry Pi
with the simplecard driver.

Annaliese McDermond (13):
  ASoC: tlv320aic32x4: Break out clock setting into separate function
  ASoC: tlv320aic32x4: Model PLL in CCF
  ASoC: tlv320aic32x4: Model CODEC_CLKIN in CCF
  ASoC: tlv320aic32x4: Model DAC/ADC dividers in CCF
  ASoC: tlv320aic32x4: Model BDIV divider in CCF
  ASoC: tlv320aic32x4: Control clock gating with CCF
  ASoC: tlv320aic32x4: Move aosr and dosr setting to separate functions
  ASoC: tlv320aic32x4: Dynamically Determine Clocking
  ASoC: tlv320aic32x4: Fix clock activation on bias level change
  ASoC: tlv320aic32x4: Remove sysclk references
  ASoC: tlv320aic32x4: Remove mclk references
  ASoC: tlv320aic32x4: Propery Set Processing Blocks
  ASoC: tlv320aic32x4: Allow 192000 Sample Rate

 sound/soc/codecs/Makefile            |   2 +-
 sound/soc/codecs/tlv320aic32x4-clk.c | 483 +++++++++++++++++++++++++++
 sound/soc/codecs/tlv320aic32x4.c     | 374 ++++++++++-----------
 sound/soc/codecs/tlv320aic32x4.h     |  11 +
 4 files changed, 670 insertions(+), 200 deletions(-)
 create mode 100644 sound/soc/codecs/tlv320aic32x4-clk.c

-- 
Annaliese McDermond
nh6z@nh6z.net

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 01/13] ASoC: tlv320aic32x4: Break out clock setting into separate function
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 02/13] ASoC: tlv320aic32x4: Model PLL in CCF Annaliese McDermond
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

Break the clock setting logic out from the main hw_params.  It's
rather large and unweildy and makes for a large function.  This
also better enables some of the following changes to the clock
tree access in the driver.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 96f1526cb258..1aa8f5aa4225 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -696,17 +696,13 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	return 0;
 }
 
-static int aic32x4_hw_params(struct snd_pcm_substream *substream,
-			     struct snd_pcm_hw_params *params,
-			     struct snd_soc_dai *dai)
+static int aic32x4_setup_clocks(struct snd_soc_component *component,
+				unsigned int sample_rate,
+				unsigned int parent_rate)
 {
-	struct snd_soc_component *component = dai->component;
-	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
-	u8 iface1_reg = 0;
-	u8 dacsetup_reg = 0;
 	int i;
 
-	i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params));
+	i = aic32x4_get_divs(parent_rate, sample_rate);
 	if (i < 0) {
 		printk(KERN_ERR "aic32x4: sampling rate not supported\n");
 		return i;
@@ -763,6 +759,20 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
 	snd_soc_component_update_bits(component, AIC32X4_BCLKN,
 			    AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
 
+	return 0;
+}
+
+static int aic32x4_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_component *component = dai->component;
+	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
+	u8 iface1_reg = 0;
+	u8 dacsetup_reg = 0;
+
+	aic32x4_setup_clocks(component, params_rate(params), aic32x4->sysclk);
+
 	switch (params_width(params)) {
 	case 16:
 		iface1_reg |= (AIC32X4_WORD_LEN_16BITS <<
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 02/13] ASoC: tlv320aic32x4: Model PLL in CCF
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 01/13] ASoC: tlv320aic32x4: Break out clock setting into separate function Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19 15:26   ` Mark Brown
  2019-03-19  3:37 ` [PATCH 03/13] ASoC: tlv320aic32x4: Model CODEC_CLKIN " Annaliese McDermond
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

Model and manage the on-board PLL as a component in the Core
Clock Framework.  This should allow us to do some more complex
clock management and power control.  Also, some of the
on-board chip clocks can be exposed to the outside, and this
change will make those clocks easier to consume by other
parts of the kernel.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/Makefile            |   2 +-
 sound/soc/codecs/tlv320aic32x4-clk.c | 323 +++++++++++++++++++++++++++
 sound/soc/codecs/tlv320aic32x4.c     |  93 ++++----
 sound/soc/codecs/tlv320aic32x4.h     |   5 +
 4 files changed, 379 insertions(+), 44 deletions(-)

diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index aab2ad95a137..c0c9a07975ad 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -192,7 +192,7 @@ snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
 snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
 snd-soc-tlv320aic26-objs := tlv320aic26.o
 snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
-snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
+snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o tlv320aic32x4-clk.o
 snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o
 snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o
 snd-soc-tlv320aic3x-objs := tlv320aic3x.o
diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
new file mode 100644
index 000000000000..9db31ca62b35
--- /dev/null
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -0,0 +1,323 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/sound/soc/codecs/tlv320aic32x4-clk.c
+ *
+ * Copyright 2019 Annaliese McDermond
+ *
+ * Author: Annaliese McDermond <nh6z@nh6z.net>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+
+#include "tlv320aic32x4.h"
+
+#define to_clk_aic32x4(_hw) container_of(_hw, struct clk_aic32x4, hw)
+struct clk_aic32x4 {
+	struct clk_hw hw;
+	struct device *dev;
+	struct regmap *regmap;
+	unsigned int reg;
+};
+
+/*
+ * struct clk_aic32x4_pll_muldiv - Multiplier/divider settings
+ * @p:		Divider
+ * @r:		first multiplier
+ * @j:		integer part of second multiplier
+ * @d:		decimal part of second multiplier
+ */
+struct clk_aic32x4_pll_muldiv {
+	u8 p;
+	u16 r;
+	u8 j;
+	u16 d;
+};
+
+struct aic32x4_clkdesc {
+	const char *name;
+	const char * const *parent_names;
+	unsigned int num_parents;
+	const struct clk_ops *ops;
+	unsigned int reg;
+};
+
+static int clk_aic32x4_pll_enable(struct clk_hw *hw)
+{
+	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
+
+	return regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
+				AIC32X4_PLLEN, AIC32X4_PLLEN);
+}
+
+static void clk_aic32x4_pll_disable(struct clk_hw *hw)
+{
+	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
+
+	regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
+				AIC32X4_PLLEN, 0);
+}
+
+static int clk_aic32x4_pll_is_enabled(struct clk_hw *hw)
+{
+	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
+
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
+	if (ret < 0)
+		return ret;
+
+	return !!(val & AIC32X4_PLLEN);
+}
+
+static int clk_aic32x4_pll_get_muldiv(struct clk_aic32x4 *pll,
+			struct clk_aic32x4_pll_muldiv *settings)
+{
+	/*	Change to use regmap_bulk_read? */
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
+	if (ret)
+		return ret;
+	settings->r = val & AIC32X4_PLL_R_MASK;
+	settings->p = (val & AIC32X4_PLL_P_MASK) >> AIC32X4_PLL_P_SHIFT;
+
+	ret = regmap_read(pll->regmap, AIC32X4_PLLJ, &val);
+	if (ret < 0)
+		return ret;
+	settings->j = val;
+
+	ret = regmap_read(pll->regmap, AIC32X4_PLLDMSB, &val);
+	if (ret < 0)
+		return ret;
+	settings->d = val << 8;
+
+	ret = regmap_read(pll->regmap, AIC32X4_PLLDLSB,	 &val);
+	if (ret < 0)
+		return ret;
+	settings->d |= val;
+
+	return 0;
+}
+
+static int clk_aic32x4_pll_set_muldiv(struct clk_aic32x4 *pll,
+			struct clk_aic32x4_pll_muldiv *settings)
+{
+	int ret;
+	/*	Change to use regmap_bulk_write for some if not all? */
+
+	ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
+				AIC32X4_PLL_R_MASK, settings->r);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_update_bits(pll->regmap, AIC32X4_PLLPR,
+				AIC32X4_PLL_P_MASK,
+				settings->p << AIC32X4_PLL_P_SHIFT);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(pll->regmap, AIC32X4_PLLJ, settings->j);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(pll->regmap, AIC32X4_PLLDMSB, (settings->d >> 8));
+	if (ret < 0)
+		return ret;
+	ret = regmap_write(pll->regmap, AIC32X4_PLLDLSB, (settings->d & 0xff));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static unsigned long clk_aic32x4_pll_calc_rate(
+			struct clk_aic32x4_pll_muldiv *settings,
+			unsigned long parent_rate)
+{
+	u64 rate;
+	/*
+	 * We scale j by 10000 to account for the decimal part of P and divide
+	 * it back out later.
+	 */
+	rate = (u64) parent_rate * settings->r *
+				((settings->j * 10000) + settings->d);
+
+	return (unsigned long) DIV_ROUND_UP_ULL(rate, settings->p * 10000);
+}
+
+static int clk_aic32x4_pll_calc_muldiv(struct clk_aic32x4_pll_muldiv *settings,
+			unsigned long rate, unsigned long parent_rate)
+{
+	u64 multiplier;
+
+	settings->p = parent_rate / AIC32X4_MAX_PLL_CLKIN + 1;
+	if (settings->p > 8)
+		return -1;
+
+	/*
+	 * We scale this figure by 10000 so that we can get the decimal part
+	 * of the multiplier.	This is because we can't do floating point
+	 * math in the kernel.
+	 */
+	 multiplier = (u64) rate * settings->p * 10000;
+	 do_div(multiplier, parent_rate);
+
+	/*
+	 * J can't be over 64, so R can scale this.
+	 * R can't be greater than 4.
+	 */
+	settings->r = ((u32) multiplier / 640000) + 1;
+	if (settings->r > 4)
+		return -1;
+	do_div(multiplier, settings->r);
+
+	/*
+	 * J can't be < 1.
+	 */
+	if (multiplier < 10000)
+		return -1;
+
+	/* Figure out the integer part, J, and the fractional part, D. */
+	settings->j = (u32) multiplier / 10000;
+	settings->d = (u32) multiplier % 10000;
+
+	return 0;
+}
+
+static unsigned long clk_aic32x4_pll_recalc_rate(struct clk_hw *hw,
+			unsigned long parent_rate)
+{
+	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
+	struct clk_aic32x4_pll_muldiv settings;
+	int ret;
+
+	ret =  clk_aic32x4_pll_get_muldiv(pll, &settings);
+	if (ret < 0)
+		return 0;
+
+	return clk_aic32x4_pll_calc_rate(&settings, parent_rate);
+}
+
+static long clk_aic32x4_pll_round_rate(struct clk_hw *hw,
+			unsigned long rate,
+			unsigned long *parent_rate)
+{
+	struct clk_aic32x4_pll_muldiv settings;
+	int ret;
+
+	ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, *parent_rate);
+	if (ret < 0)
+		return 0;
+
+	return clk_aic32x4_pll_calc_rate(&settings, *parent_rate);
+}
+
+static int clk_aic32x4_pll_set_rate(struct clk_hw *hw,
+			unsigned long rate,
+			unsigned long parent_rate)
+{
+	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
+	struct clk_aic32x4_pll_muldiv settings;
+	int ret;
+
+	ret = clk_aic32x4_pll_calc_muldiv(&settings, rate, parent_rate);
+	if (ret < 0)
+		return -EINVAL;
+
+	return clk_aic32x4_pll_set_muldiv(pll, &settings);
+}
+
+static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
+
+	return regmap_update_bits(pll->regmap,
+				AIC32X4_CLKMUX,
+				AIC32X4_PLL_CLKIN_MASK,
+				index << AIC32X4_PLL_CLKIN_SHIFT);
+}
+
+static u8 clk_aic32x4_pll_get_parent(struct clk_hw *hw)
+{
+	struct clk_aic32x4 *pll = to_clk_aic32x4(hw);
+	unsigned int val;
+
+	regmap_read(pll->regmap, AIC32X4_PLLPR, &val);
+
+	return (val & AIC32X4_PLL_CLKIN_MASK) >> AIC32X4_PLL_CLKIN_SHIFT;
+}
+
+
+static const struct clk_ops aic32x4_pll_ops = {
+	.enable = clk_aic32x4_pll_enable,
+	.disable = clk_aic32x4_pll_disable,
+	.is_enabled = clk_aic32x4_pll_is_enabled,
+	.recalc_rate = clk_aic32x4_pll_recalc_rate,
+	.round_rate = clk_aic32x4_pll_round_rate,
+	.set_rate = clk_aic32x4_pll_set_rate,
+	.set_parent = clk_aic32x4_pll_set_parent,
+	.get_parent = clk_aic32x4_pll_get_parent,
+};
+
+static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
+	{
+		.name = "pll",
+		.parent_names =
+			(const char* []) { "mclk", "bclk", "gpio", "din" },
+		.num_parents = 4,
+		.ops = &aic32x4_pll_ops,
+		.reg = 0,
+	},
+};
+
+static struct clk *aic32x4_register_clk(struct device *dev,
+			struct aic32x4_clkdesc *desc)
+{
+	struct clk_init_data init;
+	struct clk_aic32x4 *priv;
+	const char *devname = dev_name(dev);
+
+	init.ops = desc->ops;
+	init.name = desc->name;
+	init.parent_names = desc->parent_names;
+	init.num_parents = desc->num_parents;
+	init.flags = 0;
+
+	priv = devm_kzalloc(dev, sizeof(struct clk_aic32x4), GFP_KERNEL);
+	if (priv == NULL)
+		return (struct clk *) -ENOMEM;
+
+	priv->dev = dev;
+	priv->hw.init = &init;
+	priv->regmap = dev_get_regmap(dev, NULL);
+	priv->reg = desc->reg;
+
+	clk_hw_register_clkdev(&priv->hw, desc->name, devname);
+	return devm_clk_register(dev, &priv->hw);
+}
+
+int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
+{
+	int i;
+
+	/*
+	 * These lines are here to preserve the current functionality of
+	 * the driver with regard to the DT.  These should eventually be set
+	 * by DT nodes so that the connections can be set up in configuration
+	 * rather than code.
+	 */
+	aic32x4_clkdesc_array[0].parent_names =
+			(const char* []) { mclk_name, "bclk", "gpio", "din" };
+
+	for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
+		aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
+
+	return 0;
+}
+EXPORT_SYMBOL(aic32x4_register_clocks);
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 1aa8f5aa4225..0e0af3a3cdf9 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -33,6 +33,7 @@
 #include <linux/cdev.h>
 #include <linux/slab.h>
 #include <linux/clk.h>
+#include <linux/of_clk.h>
 #include <linux/regulator/consumer.h>
 
 #include <sound/tlv320aic32x4.h>
@@ -49,9 +50,7 @@
 struct aic32x4_rate_divs {
 	u32 mclk;
 	u32 rate;
-	u8 p_val;
-	u8 pll_j;
-	u16 pll_d;
+	unsigned long pll_rate;
 	u16 dosr;
 	u8 ndac;
 	u8 mdac;
@@ -69,6 +68,7 @@ struct aic32x4_priv {
 	bool swapdacs;
 	int rstn_gpio;
 	struct clk *mclk;
+	const char *mclk_name;
 
 	struct regulator *supply_ldo;
 	struct regulator *supply_iov;
@@ -307,34 +307,34 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
 
 static const struct aic32x4_rate_divs aic32x4_divs[] = {
 	/* 8k rate */
-	{12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24},
-	{24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24},
-	{25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24},
+	{ 12000000, 8000, 57120000, 768, 5, 3, 128, 5, 18, 24 },
+	{ 24000000, 8000, 57120000, 768, 15, 1, 64, 45, 4, 24 },
+	{ 25000000, 8000, 32620000, 768, 15, 1, 64, 45, 4, 24 },
 	/* 11.025k rate */
-	{12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16},
-	{24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16},
+	{ 12000000, 11025, 44217600, 512, 8, 2, 128, 8, 8, 16 },
+	{ 24000000, 11025, 44217600, 512, 16, 1, 64, 32, 4, 16 },
 	/* 16k rate */
-	{12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12},
-	{24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12},
-	{25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12},
+	{ 12000000, 16000, 57120000, 384, 5, 3, 128, 5, 9, 12 },
+	{ 24000000, 16000, 57120000, 384, 15, 1, 64, 18, 5, 12 },
+	{ 25000000, 16000, 32620000, 384, 15, 1, 64, 18, 5, 12 },
 	/* 22.05k rate */
-	{12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8},
-	{24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8},
-	{25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8},
+	{ 12000000, 22050, 44217600, 256, 4, 4, 128, 4, 8, 8 },
+	{ 24000000, 22050, 44217600, 256, 16, 1, 64, 16, 4, 8 },
+	{ 25000000, 22050, 19713750, 256, 16, 1, 64, 16, 4, 8 },
 	/* 32k rate */
-	{12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6},
-	{24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6},
+	{ 12000000, 32000, 14112000, 192, 2, 7, 64, 2, 21, 6 },
+	{ 24000000, 32000, 14112000, 192, 7, 2, 64, 7, 6, 6 },
 	/* 44.1k rate */
-	{12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4},
-	{24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4},
-	{25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4},
+	{ 12000000, 44100, 44217600, 128, 2, 8, 128, 2, 8, 4 },
+	{ 24000000, 44100, 44217600, 128, 8, 2, 64, 8, 4, 4 },
+	{ 25000000, 44100, 19713750, 128, 8, 2, 64, 8, 4, 4 },
 	/* 48k rate */
-	{12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4},
-	{24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4},
-	{25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4},
+	{ 12000000, 48000, 18432000, 128, 2, 8, 128, 2, 8, 4 },
+	{ 24000000, 48000, 18432000, 128, 8, 2, 64, 8, 4, 4 },
+	{ 25000000, 48000, 75626250, 128, 8, 2, 64, 8, 4, 4 },
 
 	/* 96k rate */
-	{25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1},
+	{ 25000000, 96000, 75626250, 64, 4, 4, 64, 4, 4, 1 },
 };
 
 static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
@@ -701,6 +701,11 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 				unsigned int parent_rate)
 {
 	int i;
+	int ret;
+
+	struct clk_bulk_data clocks[] = {
+		{ .id = "pll" },
+	};
 
 	i = aic32x4_get_divs(parent_rate, sample_rate);
 	if (i < 0) {
@@ -708,30 +713,20 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 		return i;
 	}
 
-	/* MCLK as PLL_CLKIN */
-	snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_PLL_CLKIN_MASK,
-			    AIC32X4_PLL_CLKIN_MCLK << AIC32X4_PLL_CLKIN_SHIFT);
+	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
+	if (ret)
+		return ret;
+
+	clk_set_rate(clocks[0].clk, sample_rate);
+
 	/* PLL as CODEC_CLKIN */
-	snd_soc_component_update_bits(component, AIC32X4_CLKMUX, AIC32X4_CODEC_CLKIN_MASK,
+	snd_soc_component_update_bits(component, AIC32X4_CLKMUX,
+			AIC32X4_CODEC_CLKIN_MASK,
 			AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
 	/* DAC_MOD_CLK as BDIV_CLKIN */
 	snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
 				AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
 
-	/* We will fix R value to 1 and will make P & J=K.D as variable */
-	snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_R_MASK, 0x01);
-
-	/* PLL P value */
-	snd_soc_component_update_bits(component, AIC32X4_PLLPR, AIC32X4_PLL_P_MASK,
-			    aic32x4_divs[i].p_val << AIC32X4_PLL_P_SHIFT);
-
-	/* PLL J value */
-	snd_soc_component_write(component, AIC32X4_PLLJ, aic32x4_divs[i].pll_j);
-
-	/* PLL D value */
-	snd_soc_component_write(component, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8));
-	snd_soc_component_write(component, AIC32X4_PLLDLSB, (aic32x4_divs[i].pll_d & 0xff));
-
 	/* NDAC divider value */
 	snd_soc_component_update_bits(component, AIC32X4_NDAC,
 				AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
@@ -990,8 +985,8 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
 
 	/* Power platform configuration */
 	if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
-		snd_soc_component_write(component, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN |
-						      AIC32X4_MICBIAS_2075V);
+		snd_soc_component_write(component, AIC32X4_MICBIAS,
+				AIC32X4_MICBIAS_LDOIN | AIC32X4_MICBIAS_2075V);
 	}
 	if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE)
 		snd_soc_component_write(component, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE);
@@ -1054,12 +1049,18 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4,
 		struct device_node *np)
 {
 	struct aic32x4_setup_data *aic32x4_setup;
+	int ret;
 
 	aic32x4_setup = devm_kzalloc(aic32x4->dev, sizeof(*aic32x4_setup),
 							GFP_KERNEL);
 	if (!aic32x4_setup)
 		return -ENOMEM;
 
+	ret = of_property_match_string(np, "clock-names", "mclk");
+	if (ret < 0)
+		return -EINVAL;
+	aic32x4->mclk_name = of_clk_get_parent_name(np, ret);
+
 	aic32x4->swapdacs = false;
 	aic32x4->micpga_routing = 0;
 	aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0);
@@ -1193,6 +1194,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
 		aic32x4->swapdacs = pdata->swapdacs;
 		aic32x4->micpga_routing = pdata->micpga_routing;
 		aic32x4->rstn_gpio = pdata->rstn_gpio;
+		aic32x4->mclk_name = "mclk";
 	} else if (np) {
 		ret = aic32x4_parse_dt(aic32x4, np);
 		if (ret) {
@@ -1204,6 +1206,7 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
 		aic32x4->swapdacs = false;
 		aic32x4->micpga_routing = 0;
 		aic32x4->rstn_gpio = -1;
+		aic32x4->mclk_name = "mclk";
 	}
 
 	aic32x4->mclk = devm_clk_get(dev, "mclk");
@@ -1212,6 +1215,10 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
 		return PTR_ERR(aic32x4->mclk);
 	}
 
+	ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
+	if (ret)
+		return ret;
+
 	if (gpio_is_valid(aic32x4->rstn_gpio)) {
 		ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio,
 				GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index c2d74025bf4b..e2b65bbba7c2 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -16,6 +16,7 @@ struct regmap_config;
 extern const struct regmap_config aic32x4_regmap_config;
 int aic32x4_probe(struct device *dev, struct regmap *regmap);
 int aic32x4_remove(struct device *dev);
+int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
 
 /* tlv320aic32x4 register space (in decimal to match datasheet) */
 
@@ -205,4 +206,8 @@ int aic32x4_remove(struct device *dev);
 #define AIC32X4_RMICPGANIN_IN1L_10K	0x10
 #define AIC32X4_RMICPGANIN_CM1R_10K	0x40
 
+/* Clock Limits */
+#define AIC32X4_MAX_PLL_CLKIN		20000000
+
+
 #endif				/* _TLV320AIC32X4_H */
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 03/13] ASoC: tlv320aic32x4: Model CODEC_CLKIN in CCF
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 01/13] ASoC: tlv320aic32x4: Break out clock setting into separate function Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 02/13] ASoC: tlv320aic32x4: Model PLL in CCF Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 04/13] ASoC: tlv320aic32x4: Model DAC/ADC dividers " Annaliese McDermond
                   ` (9 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

Model and manage codec clock input as a component in the Core
Clock Framework.  This should allow us to do some more complex
clock management and power control.  Also, some of the
on-board chip clocks can be exposed to the outside, and this
change will make those clocks easier to consume by other
parts of the kernel.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4-clk.c | 34 ++++++++++++++++++++++++++++
 sound/soc/codecs/tlv320aic32x4.c     | 18 +++++++++++----
 2 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
index 9db31ca62b35..e9c4bec795db 100644
--- a/sound/soc/codecs/tlv320aic32x4-clk.c
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -265,6 +265,30 @@ static const struct clk_ops aic32x4_pll_ops = {
 	.get_parent = clk_aic32x4_pll_get_parent,
 };
 
+static int clk_aic32x4_codec_clkin_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
+
+	return regmap_update_bits(mux->regmap,
+		AIC32X4_CLKMUX,
+		AIC32X4_CODEC_CLKIN_MASK, index << AIC32X4_CODEC_CLKIN_SHIFT);
+}
+
+static u8 clk_aic32x4_codec_clkin_get_parent(struct clk_hw *hw)
+{
+	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
+	unsigned int val;
+
+	regmap_read(mux->regmap, AIC32X4_CLKMUX, &val);
+
+	return (val & AIC32X4_CODEC_CLKIN_MASK) >> AIC32X4_CODEC_CLKIN_SHIFT;
+}
+
+static const struct clk_ops aic32x4_codec_clkin_ops = {
+	.set_parent = clk_aic32x4_codec_clkin_set_parent,
+	.get_parent = clk_aic32x4_codec_clkin_get_parent,
+};
+
 static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
 	{
 		.name = "pll",
@@ -274,6 +298,14 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
 		.ops = &aic32x4_pll_ops,
 		.reg = 0,
 	},
+	{
+		.name = "codec_clkin",
+		.parent_names =
+			(const char *[]) { "mclk", "bclk", "gpio", "pll" },
+		.num_parents = 4,
+		.ops = &aic32x4_codec_clkin_ops,
+		.reg = 0,
+	},
 };
 
 static struct clk *aic32x4_register_clk(struct device *dev,
@@ -314,6 +346,8 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name)
 	 */
 	aic32x4_clkdesc_array[0].parent_names =
 			(const char* []) { mclk_name, "bclk", "gpio", "din" };
+	aic32x4_clkdesc_array[1].parent_names =
+			(const char *[]) { mclk_name, "bclk", "gpio", "pll" };
 
 	for (i = 0; i < ARRAY_SIZE(aic32x4_clkdesc_array); ++i)
 		aic32x4_register_clk(dev, &aic32x4_clkdesc_array[i]);
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 0e0af3a3cdf9..6b682743cf9b 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -719,12 +719,9 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 
 	clk_set_rate(clocks[0].clk, sample_rate);
 
-	/* PLL as CODEC_CLKIN */
-	snd_soc_component_update_bits(component, AIC32X4_CLKMUX,
-			AIC32X4_CODEC_CLKIN_MASK,
-			AIC32X4_CODEC_CLKIN_PLL << AIC32X4_CODEC_CLKIN_SHIFT);
 	/* DAC_MOD_CLK as BDIV_CLKIN */
-	snd_soc_component_update_bits(component, AIC32X4_IFACE3, AIC32X4_BDIVCLK_MASK,
+	snd_soc_component_update_bits(component, AIC32X4_IFACE3,
+				AIC32X4_BDIVCLK_MASK,
 				AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
 
 	/* NDAC divider value */
@@ -971,6 +968,15 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
 {
 	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
 	u32 tmp_reg;
+	int ret;
+
+	struct clk_bulk_data clocks[] = {
+	    { .id = "codec_clkin" },
+	};
+
+	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
+	if (ret)
+		return ret;
 
 	if (gpio_is_valid(aic32x4->rstn_gpio)) {
 		ndelay(10);
@@ -983,6 +989,8 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
 	if (aic32x4->setup)
 		aic32x4_setup_gpios(component);
 
+	clk_set_parent(clocks[0].clk, clocks[1].clk);
+
 	/* Power platform configuration */
 	if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
 		snd_soc_component_write(component, AIC32X4_MICBIAS,
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 04/13] ASoC: tlv320aic32x4: Model DAC/ADC dividers in CCF
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (2 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 03/13] ASoC: tlv320aic32x4: Model CODEC_CLKIN " Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19 15:28   ` Mark Brown
  2019-03-19  3:37 ` [PATCH 05/13] ASoC: tlv320aic32x4: Model BDIV divider " Annaliese McDermond
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

    Model and manage DAC/ADC dividers as components in the Core
    Clock Framework.  This should allow us to do some more complex
    clock management and power control.  Also, some of the
    on-board chip clocks can be exposed to the outside, and this
    change will make those clocks easier to consume by other
    parts of the kernel.

    Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4-clk.c | 90 ++++++++++++++++++++++++++
 sound/soc/codecs/tlv320aic32x4.c     | 95 ++++++++++++++++------------
 sound/soc/codecs/tlv320aic32x4.h     |  4 ++
 3 files changed, 148 insertions(+), 41 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
index e9c4bec795db..87103b3878ab 100644
--- a/sound/soc/codecs/tlv320aic32x4-clk.c
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -289,6 +289,68 @@ static const struct clk_ops aic32x4_codec_clkin_ops = {
 	.get_parent = clk_aic32x4_codec_clkin_get_parent,
 };
 
+static int clk_aic32x4_div_enable(struct clk_hw *hw)
+{
+	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
+
+	return regmap_update_bits(div->regmap, div->reg,
+				AIC32X4_DIVEN, AIC32X4_DIVEN);
+}
+
+static void clk_aic32x4_div_disable(struct clk_hw *hw)
+{
+	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
+
+	regmap_update_bits(div->regmap, div->reg,
+			AIC32X4_DIVEN, 0);
+}
+
+static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate)
+{
+	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
+	u8 divisor;
+
+	divisor = DIV_ROUND_UP(parent_rate, rate);
+	if (divisor > 128)
+		return -EINVAL;
+
+	return regmap_update_bits(div->regmap, div->reg,
+				AIC32X4_DIV_MASK, divisor);
+}
+
+static long clk_aic32x4_div_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *parent_rate)
+{
+	unsigned long divisor;
+
+	divisor = DIV_ROUND_UP(*parent_rate, rate);
+	if (divisor > 128)
+		return -EINVAL;
+
+	return DIV_ROUND_UP(*parent_rate, divisor);
+}
+
+static unsigned long clk_aic32x4_div_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	struct clk_aic32x4 *div = to_clk_aic32x4(hw);
+
+	unsigned int val;
+
+	regmap_read(div->regmap, div->reg, &val);
+
+	return DIV_ROUND_UP(parent_rate, val & AIC32X4_DIV_MASK);
+}
+
+static const struct clk_ops aic32x4_div_ops = {
+	.enable = clk_aic32x4_div_enable,
+	.disable = clk_aic32x4_div_disable,
+	.set_rate = clk_aic32x4_div_set_rate,
+	.round_rate = clk_aic32x4_div_round_rate,
+	.recalc_rate = clk_aic32x4_div_recalc_rate,
+};
+
 static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
 	{
 		.name = "pll",
@@ -306,6 +368,34 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
 		.ops = &aic32x4_codec_clkin_ops,
 		.reg = 0,
 	},
+	{
+		.name = "ndac",
+		.parent_names = (const char * []) { "codec_clkin" },
+		.num_parents = 1,
+		.ops = &aic32x4_div_ops,
+		.reg = AIC32X4_NDAC,
+	},
+	{
+		.name = "mdac",
+		.parent_names = (const char * []) { "ndac" },
+		.num_parents = 1,
+		.ops = &aic32x4_div_ops,
+		.reg = AIC32X4_MDAC,
+	},
+	{
+		.name = "nadc",
+		.parent_names = (const char * []) { "codec_clkin" },
+		.num_parents = 1,
+		.ops = &aic32x4_div_ops,
+		.reg = AIC32X4_NADC,
+	},
+	{
+		.name = "madc",
+		.parent_names = (const char * []) { "nadc" },
+		.num_parents = 1,
+		.ops = &aic32x4_div_ops,
+		.reg = AIC32X4_MADC,
+	},
 };
 
 static struct clk *aic32x4_register_clk(struct device *dev,
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 6b682743cf9b..aac4c3f335d1 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -52,11 +52,11 @@ struct aic32x4_rate_divs {
 	u32 rate;
 	unsigned long pll_rate;
 	u16 dosr;
-	u8 ndac;
-	u8 mdac;
+	unsigned long ndac_rate;
+	unsigned long mdac_rate;
 	u8 aosr;
-	u8 nadc;
-	u8 madc;
+	unsigned long nadc_rate;
+	unsigned long madc_rate;
 	u8 blck_N;
 };
 
@@ -307,34 +307,54 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
 
 static const struct aic32x4_rate_divs aic32x4_divs[] = {
 	/* 8k rate */
-	{ 12000000, 8000, 57120000, 768, 5, 3, 128, 5, 18, 24 },
-	{ 24000000, 8000, 57120000, 768, 15, 1, 64, 45, 4, 24 },
-	{ 25000000, 8000, 32620000, 768, 15, 1, 64, 45, 4, 24 },
+	{ 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
+		1024000, 24 },
+	{ 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
+		512000, 24 },
+	{ 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
+		512000, 24 },
 	/* 11.025k rate */
-	{ 12000000, 11025, 44217600, 512, 8, 2, 128, 8, 8, 16 },
-	{ 24000000, 11025, 44217600, 512, 16, 1, 64, 32, 4, 16 },
+	{ 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
+		1411200, 16 },
+	{ 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
+		705600, 16 },
 	/* 16k rate */
-	{ 12000000, 16000, 57120000, 384, 5, 3, 128, 5, 9, 12 },
-	{ 24000000, 16000, 57120000, 384, 15, 1, 64, 18, 5, 12 },
-	{ 25000000, 16000, 32620000, 384, 15, 1, 64, 18, 5, 12 },
+	{ 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
+		2048000, 12 },
+	{ 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
+		1024000, 12 },
+	{ 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
+		1024000, 12 },
 	/* 22.05k rate */
-	{ 12000000, 22050, 44217600, 256, 4, 4, 128, 4, 8, 8 },
-	{ 24000000, 22050, 44217600, 256, 16, 1, 64, 16, 4, 8 },
-	{ 25000000, 22050, 19713750, 256, 16, 1, 64, 16, 4, 8 },
+	{ 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
+		2822400, 8 },
+	{ 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
+		1411200, 8 },
+	{ 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
+		1411200, 8 },
 	/* 32k rate */
-	{ 12000000, 32000, 14112000, 192, 2, 7, 64, 2, 21, 6 },
-	{ 24000000, 32000, 14112000, 192, 7, 2, 64, 7, 6, 6 },
+	{ 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
+		2048000, 6 },
+	{ 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
+		2048000, 6 },
 	/* 44.1k rate */
-	{ 12000000, 44100, 44217600, 128, 2, 8, 128, 2, 8, 4 },
-	{ 24000000, 44100, 44217600, 128, 8, 2, 64, 8, 4, 4 },
-	{ 25000000, 44100, 19713750, 128, 8, 2, 64, 8, 4, 4 },
+	{ 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
+		5644800, 4 },
+	{ 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
+		2822400, 4 },
+	{ 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
+		2822400, 4 },
 	/* 48k rate */
-	{ 12000000, 48000, 18432000, 128, 2, 8, 128, 2, 8, 4 },
-	{ 24000000, 48000, 18432000, 128, 8, 2, 64, 8, 4, 4 },
-	{ 25000000, 48000, 75626250, 128, 8, 2, 64, 8, 4, 4 },
+	{ 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
+		6144000, 4 },
+	{ 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
+		3072000, 4 },
+	{ 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
+		3072000, 4 },
 
 	/* 96k rate */
-	{ 25000000, 96000, 75626250, 64, 4, 4, 64, 4, 4, 1 },
+	{ 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
+		6144000, 1 },
 };
 
 static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
@@ -705,6 +725,10 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 
 	struct clk_bulk_data clocks[] = {
 		{ .id = "pll" },
+		{ .id = "nadc" },
+		{ .id = "madc" },
+		{ .id = "ndac" },
+		{ .id = "mdac" },
 	};
 
 	i = aic32x4_get_divs(parent_rate, sample_rate);
@@ -717,33 +741,21 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 	if (ret)
 		return ret;
 
-	clk_set_rate(clocks[0].clk, sample_rate);
+	clk_set_rate(clocks[0].clk, aic32x4_divs[i].pll_rate);
+	clk_set_rate(clocks[1].clk, aic32x4_divs[i].nadc_rate);
+	clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
+	clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
+	clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
 
 	/* DAC_MOD_CLK as BDIV_CLKIN */
 	snd_soc_component_update_bits(component, AIC32X4_IFACE3,
 				AIC32X4_BDIVCLK_MASK,
 				AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
 
-	/* NDAC divider value */
-	snd_soc_component_update_bits(component, AIC32X4_NDAC,
-				AIC32X4_NDAC_MASK, aic32x4_divs[i].ndac);
-
-	/* MDAC divider value */
-	snd_soc_component_update_bits(component, AIC32X4_MDAC,
-				AIC32X4_MDAC_MASK, aic32x4_divs[i].mdac);
-
 	/* DOSR MSB & LSB values */
 	snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
 	snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
 
-	/* NADC divider value */
-	snd_soc_component_update_bits(component, AIC32X4_NADC,
-				AIC32X4_NADC_MASK, aic32x4_divs[i].nadc);
-
-	/* MADC divider value */
-	snd_soc_component_update_bits(component, AIC32X4_MADC,
-				AIC32X4_MADC_MASK, aic32x4_divs[i].madc);
-
 	/* AOSR value */
 	snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
 
@@ -972,6 +984,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
 
 	struct clk_bulk_data clocks[] = {
 		{ .id = "codec_clkin" },
+		{ .id = "pll" },
 	};
 
 	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index e2b65bbba7c2..6ede877b00a0 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -206,6 +206,10 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
 #define AIC32X4_RMICPGANIN_IN1L_10K	0x10
 #define AIC32X4_RMICPGANIN_CM1R_10K	0x40
 
+/* Common mask and enable for all of the dividers */
+#define AIC32X4_DIVEN           BIT(7)
+#define AIC32X4_DIV_MASK        GENMASK(6, 0)
+
 /* Clock Limits */
 #define AIC32X4_MAX_PLL_CLKIN		20000000
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 05/13] ASoC: tlv320aic32x4: Model BDIV divider in CCF
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (3 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 04/13] ASoC: tlv320aic32x4: Model DAC/ADC dividers " Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 06/13] ASoC: tlv320aic32x4: Control clock gating with CCF Annaliese McDermond
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

Model and manage BDIV divider as components in the Core
Clock Framework.  This should allow us to do some more complex
clock management and power control.  Also, some of the
on-board chip clocks can be exposed to the outside, and this
change will make those clocks easier to consume by other
parts of the kernel.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4-clk.c | 36 ++++++++++++++++++
 sound/soc/codecs/tlv320aic32x4.c     | 56 +++++++++++++---------------
 2 files changed, 62 insertions(+), 30 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4-clk.c b/sound/soc/codecs/tlv320aic32x4-clk.c
index 87103b3878ab..2995ab47cb0f 100644
--- a/sound/soc/codecs/tlv320aic32x4-clk.c
+++ b/sound/soc/codecs/tlv320aic32x4-clk.c
@@ -351,6 +351,34 @@ static const struct clk_ops aic32x4_div_ops = {
 	.recalc_rate = clk_aic32x4_div_recalc_rate,
 };
 
+static int clk_aic32x4_bdiv_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
+
+	return regmap_update_bits(mux->regmap, AIC32X4_IFACE3,
+				AIC32X4_BDIVCLK_MASK, index);
+}
+
+static u8 clk_aic32x4_bdiv_get_parent(struct clk_hw *hw)
+{
+	struct clk_aic32x4 *mux = to_clk_aic32x4(hw);
+	unsigned int val;
+
+	regmap_read(mux->regmap, AIC32X4_IFACE3, &val);
+
+	return val & AIC32X4_BDIVCLK_MASK;
+}
+
+static const struct clk_ops aic32x4_bdiv_ops = {
+	.enable = clk_aic32x4_div_enable,
+	.disable = clk_aic32x4_div_disable,
+	.set_parent = clk_aic32x4_bdiv_set_parent,
+	.get_parent = clk_aic32x4_bdiv_get_parent,
+	.set_rate = clk_aic32x4_div_set_rate,
+	.round_rate = clk_aic32x4_div_round_rate,
+	.recalc_rate = clk_aic32x4_div_recalc_rate,
+};
+
 static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
 	{
 		.name = "pll",
@@ -396,6 +424,14 @@ static struct aic32x4_clkdesc aic32x4_clkdesc_array[] = {
 		.ops = &aic32x4_div_ops,
 		.reg = AIC32X4_MADC,
 	},
+	{
+		.name = "bdiv",
+		.parent_names =
+			(const char *[]) { "ndac", "mdac", "nadc", "madc" },
+		.num_parents = 4,
+		.ops = &aic32x4_bdiv_ops,
+		.reg = AIC32X4_BCLKN,
+	},
 };
 
 static struct clk *aic32x4_register_clk(struct device *dev,
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index aac4c3f335d1..4e170cdc05ce 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -57,7 +57,7 @@ struct aic32x4_rate_divs {
 	u8 aosr;
 	unsigned long nadc_rate;
 	unsigned long madc_rate;
-	u8 blck_N;
+	unsigned long bdiv_rate;
 };
 
 struct aic32x4_priv {
@@ -308,53 +308,53 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
 static const struct aic32x4_rate_divs aic32x4_divs[] = {
 	/* 8k rate */
 	{ 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
-		1024000, 24 },
+		1024000, 256000 },
 	{ 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
-		512000, 24 },
+		512000, 256000 },
 	{ 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
-		512000, 24 },
+		512000, 256000 },
 	/* 11.025k rate */
 	{ 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
-		1411200, 16 },
+		1411200, 352800 },
 	{ 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
-		705600, 16 },
+		705600, 352800 },
 	/* 16k rate */
 	{ 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
-		2048000, 12 },
+		2048000, 512000 },
 	{ 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
-		1024000, 12 },
+		1024000, 512000 },
 	{ 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
-		1024000, 12 },
+		1024000, 512000 },
 	/* 22.05k rate */
 	{ 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
-		2822400, 8 },
+		2822400, 705600 },
 	{ 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
-		1411200, 8 },
+		1411200, 705600 },
 	{ 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
-		1411200, 8 },
+		1411200, 705600 },
 	/* 32k rate */
 	{ 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
-		2048000, 6 },
+		2048000, 1024000 },
 	{ 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
-		2048000, 6 },
+		2048000, 1024000 },
 	/* 44.1k rate */
 	{ 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
-		5644800, 4 },
+		5644800, 1411200 },
 	{ 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
-		2822400, 4 },
+		2822400, 1411200 },
 	{ 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
-		2822400, 4 },
+		2822400, 1411200 },
 	/* 48k rate */
 	{ 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
-		6144000, 4 },
+		6144000, 1536000 },
 	{ 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
-		3072000, 4 },
+		3072000, 1536000 },
 	{ 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
-		3072000, 4 },
+		3072000, 1536000 },
 
 	/* 96k rate */
 	{ 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
-		6144000, 1 },
+		6144000, 3072000 },
 };
 
 static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
@@ -729,6 +729,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 		{ .id = "madc" },
 		{ .id = "ndac" },
 		{ .id = "mdac" },
+		{ .id = "bdiv" },
 	};
 
 	i = aic32x4_get_divs(parent_rate, sample_rate);
@@ -746,11 +747,7 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 	clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
 	clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
 	clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
-
-	/* DAC_MOD_CLK as BDIV_CLKIN */
-	snd_soc_component_update_bits(component, AIC32X4_IFACE3,
-				AIC32X4_BDIVCLK_MASK,
-				AIC32X4_DACMOD2BCLK << AIC32X4_BDIVCLK_SHIFT);
+	clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
 
 	/* DOSR MSB & LSB values */
 	snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
@@ -759,10 +756,6 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 	/* AOSR value */
 	snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
 
-	/* BCLK N divider */
-	snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-				AIC32X4_BCLK_MASK, aic32x4_divs[i].blck_N);
-
 	return 0;
 }
 
@@ -985,6 +978,8 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
 	struct clk_bulk_data clocks[] = {
 		{ .id = "codec_clkin" },
 		{ .id = "pll" },
+		{ .id = "bdiv" },
+		{ .id = "mdac" },
 	};
 
 	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
@@ -1003,6 +998,7 @@ static int aic32x4_component_probe(struct snd_soc_component *component)
 		aic32x4_setup_gpios(component);
 
 	clk_set_parent(clocks[0].clk, clocks[1].clk);
+	clk_set_parent(clocks[2].clk, clocks[3].clk);
 
 	/* Power platform configuration */
 	if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) {
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 06/13] ASoC: tlv320aic32x4: Control clock gating with CCF
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (4 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 05/13] ASoC: tlv320aic32x4: Model BDIV divider " Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 07/13] ASoC: tlv320aic32x4: Move aosr and dosr setting to separate functions Annaliese McDermond
                   ` (6 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

Control the clock gating to the various clock components to use
the CCF.  This allows us to prepare_enalbe only 3 clocks and the
relationships assigned to them will cause upstream clockss to
enable automatically.  Additionally we can do this in a single
call to the CCF.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 71 ++++++--------------------------
 1 file changed, 13 insertions(+), 58 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 4e170cdc05ce..ecf692e346b6 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -818,75 +818,30 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute)
 static int aic32x4_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
-	struct aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
 	int ret;
 
+	struct clk_bulk_data clocks[] = {
+		{ .id = "madc" },
+		{ .id = "mdac" },
+		{ .id = "bdiv" },
+	};
+
+	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
+	if (ret)
+		return ret;
+
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		/* Switch on master clock */
-		ret = clk_prepare_enable(aic32x4->mclk);
+		ret = clk_bulk_prepare_enable(ARRAY_SIZE(clocks), clocks);
 		if (ret) {
-			dev_err(component->dev, "Failed to enable master clock\n");
+			dev_err(component->dev, "Failed to enable clocks\n");
 			return ret;
 		}
-
-		/* Switch on PLL */
-		snd_soc_component_update_bits(component, AIC32X4_PLLPR,
-					AIC32X4_PLLEN, AIC32X4_PLLEN);
-
-		/* Switch on NDAC Divider */
-		snd_soc_component_update_bits(component, AIC32X4_NDAC,
-					AIC32X4_NDACEN, AIC32X4_NDACEN);
-
-		/* Switch on MDAC Divider */
-		snd_soc_component_update_bits(component, AIC32X4_MDAC,
-					AIC32X4_MDACEN, AIC32X4_MDACEN);
-
-		/* Switch on NADC Divider */
-		snd_soc_component_update_bits(component, AIC32X4_NADC,
-					AIC32X4_NADCEN, AIC32X4_NADCEN);
-
-		/* Switch on MADC Divider */
-		snd_soc_component_update_bits(component, AIC32X4_MADC,
-					AIC32X4_MADCEN, AIC32X4_MADCEN);
-
-		/* Switch on BCLK_N Divider */
-		snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-					AIC32X4_BCLKEN, AIC32X4_BCLKEN);
 		break;
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
-		/* Initial cold start */
-		if (snd_soc_component_get_bias_level(component) == SND_SOC_BIAS_OFF)
-			break;
-
-		/* Switch off BCLK_N Divider */
-		snd_soc_component_update_bits(component, AIC32X4_BCLKN,
-					AIC32X4_BCLKEN, 0);
-
-		/* Switch off MADC Divider */
-		snd_soc_component_update_bits(component, AIC32X4_MADC,
-					AIC32X4_MADCEN, 0);
-
-		/* Switch off NADC Divider */
-		snd_soc_component_update_bits(component, AIC32X4_NADC,
-					AIC32X4_NADCEN, 0);
-
-		/* Switch off MDAC Divider */
-		snd_soc_component_update_bits(component, AIC32X4_MDAC,
-					AIC32X4_MDACEN, 0);
-
-		/* Switch off NDAC Divider */
-		snd_soc_component_update_bits(component, AIC32X4_NDAC,
-					AIC32X4_NDACEN, 0);
-
-		/* Switch off PLL */
-		snd_soc_component_update_bits(component, AIC32X4_PLLPR,
-					AIC32X4_PLLEN, 0);
-
-		/* Switch off master clock */
-		clk_disable_unprepare(aic32x4->mclk);
+		clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
 		break;
 	case SND_SOC_BIAS_OFF:
 		break;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 07/13] ASoC: tlv320aic32x4: Move aosr and dosr setting to separate functions
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (5 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 06/13] ASoC: tlv320aic32x4: Control clock gating with CCF Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 08/13] ASoC: tlv320aic32x4: Dynamically Determine Clocking Annaliese McDermond
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

Move these to separate helper functions.  This looks cleaner and fits
better with the new clock setting in CCF.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index ecf692e346b6..1d347adbcc30 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -716,6 +716,20 @@ static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 	return 0;
 }
 
+static int aic32x4_set_aosr(struct snd_soc_component *component, u8 aosr)
+{
+	return snd_soc_component_write(component, AIC32X4_AOSR, aosr);
+}
+
+static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
+{
+	snd_soc_component_write(component, AIC32X4_DOSRMSB, dosr >> 8);
+	snd_soc_component_write(component, AIC32X4_DOSRLSB,
+		      (dosr & 0xff));
+
+	return 0;
+}
+
 static int aic32x4_setup_clocks(struct snd_soc_component *component,
 				unsigned int sample_rate,
 				unsigned int parent_rate)
@@ -748,13 +762,8 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 	clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
 	clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
 	clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
-
-	/* DOSR MSB & LSB values */
-	snd_soc_component_write(component, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8);
-	snd_soc_component_write(component, AIC32X4_DOSRLSB, (aic32x4_divs[i].dosr & 0xff));
-
-	/* AOSR value */
-	snd_soc_component_write(component, AIC32X4_AOSR, aic32x4_divs[i].aosr);
+	aic32x4_set_aosr(component, aic32x4_divs[i].aosr);
+	aic32x4_set_dosr(component, aic32x4_divs[i].dosr);
 
 	return 0;
 }
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 08/13] ASoC: tlv320aic32x4: Dynamically Determine Clocking
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (6 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 07/13] ASoC: tlv320aic32x4: Move aosr and dosr setting to separate functions Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 09/13] ASoC: tlv320aic32x4: Fix clock activation on bias level change Annaliese McDermond
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

The existing code uses a static lookup table to determine the
settings of the various clock devices on board the chip.  This is
limiting in a couple of ways.  First, this doesn't allow for any
master clock rates other than the three that have been
precalculated.  Additionally, new sample rates are difficult to
add to the table.  Witness that the chip is capable of 192000 Hz
sampling, but it is not provided by this driver.  Last, if the
driver is clocked by something that isn't a crystal, the
upstream clock may not be able to achieve exactly the rate
requested in the driver.  This will mean that clocking will be
slightly off for the sampling clock or that it won't work at all.

This patch determines the settings for all of the clocks at
runtime considering the real conditions of the clocks in the
system.  The rules for the clocks are in TI's SLAA557 application
guide on pages 37, 51 and 77.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 182 ++++++++++++++-----------------
 sound/soc/codecs/tlv320aic32x4.h |   4 +-
 2 files changed, 87 insertions(+), 99 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 1d347adbcc30..b8b97b211d46 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -47,19 +47,6 @@
 
 #include "tlv320aic32x4.h"
 
-struct aic32x4_rate_divs {
-	u32 mclk;
-	u32 rate;
-	unsigned long pll_rate;
-	u16 dosr;
-	unsigned long ndac_rate;
-	unsigned long mdac_rate;
-	u8 aosr;
-	unsigned long nadc_rate;
-	unsigned long madc_rate;
-	unsigned long bdiv_rate;
-};
-
 struct aic32x4_priv {
 	struct regmap *regmap;
 	u32 sysclk;
@@ -305,58 +292,6 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = {
 			0, 0x0F, 0),
 };
 
-static const struct aic32x4_rate_divs aic32x4_divs[] = {
-	/* 8k rate */
-	{ 12000000, 8000, 57120000, 768, 18432000, 6144000, 128, 18432000,
-		1024000, 256000 },
-	{ 24000000, 8000, 57120000, 768, 6144000, 6144000, 64, 2048000,
-		512000, 256000 },
-	{ 25000000, 8000, 32620000, 768, 6144000, 6144000, 64, 2048000,
-		512000, 256000 },
-	/* 11.025k rate */
-	{ 12000000, 11025, 44217600, 512, 11289600, 5644800, 128, 11289600,
-		1411200, 352800 },
-	{ 24000000, 11025, 44217600, 512, 5644800, 5644800, 64, 2822400,
-		705600, 352800 },
-	/* 16k rate */
-	{ 12000000, 16000, 57120000, 384, 18432000, 6144000, 128, 18432000,
-		2048000, 512000 },
-	{ 24000000, 16000, 57120000, 384, 6144000, 6144000, 64, 5120000,
-		1024000, 512000 },
-	{ 25000000, 16000, 32620000, 384, 6144000, 6144000, 64, 5120000,
-		1024000, 512000 },
-	/* 22.05k rate */
-	{ 12000000, 22050, 44217600, 256, 22579200, 5644800, 128, 22579200,
-		2822400, 705600 },
-	{ 24000000, 22050, 44217600, 256, 5644800, 5644800, 64, 5644800,
-		1411200, 705600 },
-	{ 25000000, 22050, 19713750, 256, 5644800, 5644800, 64, 5644800,
-		1411200, 705600 },
-	/* 32k rate */
-	{ 12000000, 32000, 14112000, 192, 43008000, 6144000, 64, 43008000,
-		2048000, 1024000 },
-	{ 24000000, 32000, 14112000, 192, 12288000, 6144000, 64, 12288000,
-		2048000, 1024000 },
-	/* 44.1k rate */
-	{ 12000000, 44100, 44217600, 128, 45158400, 5644800, 128, 45158400,
-		5644800, 1411200 },
-	{ 24000000, 44100, 44217600, 128, 11289600, 5644800, 64, 11289600,
-		2822400, 1411200 },
-	{ 25000000, 44100, 19713750, 128, 11289600, 5644800, 64, 11289600,
-		2822400, 1411200 },
-	/* 48k rate */
-	{ 12000000, 48000, 18432000, 128, 49152000, 6144000, 128, 49152000,
-		6144000, 1536000 },
-	{ 24000000, 48000, 18432000, 128, 12288000, 6144000, 64, 12288000,
-		3072000, 1536000 },
-	{ 25000000, 48000, 75626250, 128, 12288000, 6144000, 64, 12288000,
-		3072000, 1536000 },
-
-	/* 96k rate */
-	{ 25000000, 96000, 75626250, 64, 24576000, 6144000, 64, 24576000,
-		6144000, 3072000 },
-};
-
 static const struct snd_kcontrol_new hpl_output_mixer_controls[] = {
 	SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0),
 	SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0),
@@ -628,20 +563,6 @@ const struct regmap_config aic32x4_regmap_config = {
 };
 EXPORT_SYMBOL(aic32x4_regmap_config);
 
-static inline int aic32x4_get_divs(int mclk, int rate)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) {
-		if ((aic32x4_divs[i].rate == rate)
-			&& (aic32x4_divs[i].mclk == mclk)) {
-			return i;
-		}
-	}
-	printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n");
-	return -EINVAL;
-}
-
 static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai,
 				  int clk_id, unsigned int freq, int dir)
 {
@@ -731,11 +652,17 @@ static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
 }
 
 static int aic32x4_setup_clocks(struct snd_soc_component *component,
-				unsigned int sample_rate,
-				unsigned int parent_rate)
+				unsigned int sample_rate)
 {
-	int i;
+	u8 aosr;
+	u16 dosr;
+	u8 adc_resource_class, dac_resource_class;
+	u8 madc, nadc, mdac, ndac, max_nadc, min_mdac, max_ndac;
+	u8 dosr_increment;
+	u16 max_dosr, min_dosr;
+	unsigned long mclk_rate, adc_clock_rate, dac_clock_rate;
 	int ret;
+	struct clk *mclk;
 
 	struct clk_bulk_data clocks[] = {
 		{ .id = "pll" },
@@ -745,28 +672,87 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 		{ .id = "mdac" },
 		{ .id = "bdiv" },
 	};
-
-	i = aic32x4_get_divs(parent_rate, sample_rate);
-	if (i < 0) {
-		printk(KERN_ERR "aic32x4: sampling rate not supported\n");
-		return i;
-	}
-
 	ret = devm_clk_bulk_get(component->dev, ARRAY_SIZE(clocks), clocks);
 	if (ret)
 		return ret;
 
-	clk_set_rate(clocks[0].clk, aic32x4_divs[i].pll_rate);
-	clk_set_rate(clocks[1].clk, aic32x4_divs[i].nadc_rate);
-	clk_set_rate(clocks[2].clk, aic32x4_divs[i].madc_rate);
-	clk_set_rate(clocks[3].clk, aic32x4_divs[i].ndac_rate);
-	clk_set_rate(clocks[4].clk, aic32x4_divs[i].mdac_rate);
-	clk_set_rate(clocks[5].clk, aic32x4_divs[i].bdiv_rate);
-	aic32x4_set_aosr(component, aic32x4_divs[i].aosr);
-	aic32x4_set_dosr(component, aic32x4_divs[i].dosr);
+	mclk = clk_get_parent(clocks[1].clk);
+	mclk_rate = clk_get_rate(mclk);
+
+	if (sample_rate <= 48000) {
+		aosr = 128;
+		adc_resource_class = 6;
+		dac_resource_class = 8;
+		dosr_increment = 8;
+	} else if (sample_rate <= 96000) {
+		aosr = 64;
+		adc_resource_class = 6;
+		dac_resource_class = 8;
+		dosr_increment = 4;
+	} else if (sample_rate == 192000) {
+		aosr = 32;
+		adc_resource_class = 3;
+		dac_resource_class = 4;
+		dosr_increment = 2;
+	} else {
+		dev_err(component->dev, "Sampling rate not supported\n");
+		return -EINVAL;
+	}
 
+	madc = DIV_ROUND_UP((32 * adc_resource_class), aosr);
+	max_dosr = (AIC32X4_MAX_DOSR_FREQ / sample_rate / dosr_increment) *
+			dosr_increment;
+	min_dosr = (AIC32X4_MIN_DOSR_FREQ / sample_rate / dosr_increment) *
+			dosr_increment;
+	max_nadc = AIC32X4_MAX_CODEC_CLKIN_FREQ / (madc * aosr * sample_rate);
+
+	for (nadc = max_nadc; nadc > 0; --nadc) {
+		adc_clock_rate = nadc * madc * aosr * sample_rate;
+		for (dosr = max_dosr; dosr >= min_dosr;
+				dosr -= dosr_increment) {
+			min_mdac = DIV_ROUND_UP((32 * dac_resource_class), dosr);
+			max_ndac = AIC32X4_MAX_CODEC_CLKIN_FREQ /
+					(min_mdac * dosr * sample_rate);
+			for (mdac = min_mdac; mdac <= 128; ++mdac) {
+				for (ndac = max_ndac; ndac > 0; --ndac) {
+					dac_clock_rate = ndac * mdac * dosr *
+							sample_rate;
+					if (dac_clock_rate == adc_clock_rate) {
+						if (clk_round_rate(clocks[0].clk, dac_clock_rate) == 0)
+							continue;
+
+						clk_set_rate(clocks[0].clk,
+							dac_clock_rate);
+
+						clk_set_rate(clocks[1].clk,
+							sample_rate * aosr *
+							madc);
+						clk_set_rate(clocks[2].clk,
+							sample_rate * aosr);
+						aic32x4_set_aosr(component,
+							aosr);
+
+						clk_set_rate(clocks[3].clk,
+							sample_rate * dosr *
+							mdac);
+						clk_set_rate(clocks[4].clk,
+							sample_rate * dosr);
+						aic32x4_set_dosr(component,
+							dosr);
+
+						clk_set_rate(clocks[5].clk,
+							sample_rate * 32);
 						return 0;
 					}
+				}
+			}
+		}
+	}
+
+	dev_err(component->dev,
+		"Could not set clocks to support sample rate.\n");
+	return -EINVAL;
+}
 
 static int aic32x4_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
@@ -777,7 +763,7 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
 	u8 iface1_reg = 0;
 	u8 dacsetup_reg = 0;
 
-	aic32x4_setup_clocks(component, params_rate(params), aic32x4->sysclk);
+	aic32x4_setup_clocks(component, params_rate(params));
 
 	switch (params_width(params)) {
 	case 16:
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h
index 6ede877b00a0..88205bc97198 100644
--- a/sound/soc/codecs/tlv320aic32x4.h
+++ b/sound/soc/codecs/tlv320aic32x4.h
@@ -211,7 +211,9 @@ int aic32x4_register_clocks(struct device *dev, const char *mclk_name);
 #define AIC32X4_DIV_MASK        GENMASK(6, 0)
 
 /* Clock Limits */
+#define AIC32X4_MAX_DOSR_FREQ		6200000
+#define AIC32X4_MIN_DOSR_FREQ		2800000
+#define AIC32X4_MAX_CODEC_CLKIN_FREQ    110000000
 #define AIC32X4_MAX_PLL_CLKIN		20000000
 
-
 #endif				/* _TLV320AIC32X4_H */
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 09/13] ASoC: tlv320aic32x4: Fix clock activation on bias level change
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (7 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 08/13] ASoC: tlv320aic32x4: Dynamically Determine Clocking Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19 15:33   ` Mark Brown
  2019-03-19  3:37 ` [PATCH 10/13] ASoC: tlv320aic32x4: Remove sysclk references Annaliese McDermond
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

The clocks are double-disabled when they are first coming up
because they are already off when it first moves into STANDBY.
Check if the state is already off and leave things alone if
it is.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index b8b97b211d46..10f0e07889b7 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -814,6 +814,8 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
 				  enum snd_soc_bias_level level)
 {
 	int ret;
+	struct snd_soc_dapm_context *dapm =
+					snd_soc_component_get_dapm(component);
 
 	struct clk_bulk_data clocks[] = {
 		{ .id = "madc" },
@@ -836,6 +838,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
 	case SND_SOC_BIAS_PREPARE:
 		break;
 	case SND_SOC_BIAS_STANDBY:
+		if (dapm->bias_level != SND_SOC_BIAS_OFF)
 			clk_bulk_disable_unprepare(ARRAY_SIZE(clocks), clocks);
 		break;
 	case SND_SOC_BIAS_OFF:
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 10/13] ASoC: tlv320aic32x4: Remove sysclk references
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (8 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 09/13] ASoC: tlv320aic32x4: Fix clock activation on bias level change Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19 15:37   ` Mark Brown
  2019-03-19  3:37 ` [PATCH 11/13] ASoC: tlv320aic32x4: Remove mclk references Annaliese McDermond
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

Sysclk is not used by anything anymore.  Remove support for it.
All that information now comes from the clock tree.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 19 -------------------
 1 file changed, 19 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 10f0e07889b7..27babe48d5bc 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -49,7 +49,6 @@
 
 struct aic32x4_priv {
 	struct regmap *regmap;
-	u32 sysclk;
 	u32 power_cfg;
 	u32 micpga_routing;
 	bool swapdacs;
@@ -563,23 +562,6 @@ const struct regmap_config aic32x4_regmap_config = {
 };
 EXPORT_SYMBOL(aic32x4_regmap_config);
 
-static int aic32x4_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 aic32x4_priv *aic32x4 = snd_soc_component_get_drvdata(component);
-
-	switch (freq) {
-	case 12000000:
-	case 24000000:
-	case 25000000:
-		aic32x4->sysclk = freq;
-		return 0;
-	}
-	printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n");
-	return -EINVAL;
-}
-
 static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
 	struct snd_soc_component *component = codec_dai->component;
@@ -855,7 +837,6 @@ static const struct snd_soc_dai_ops aic32x4_ops = {
 	.hw_params = aic32x4_hw_params,
 	.digital_mute = aic32x4_mute,
 	.set_fmt = aic32x4_set_dai_fmt,
-	.set_sysclk = aic32x4_set_dai_sysclk,
 };
 
 static struct snd_soc_dai_driver aic32x4_dai = {
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 11/13] ASoC: tlv320aic32x4: Remove mclk references
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (9 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 10/13] ASoC: tlv320aic32x4: Remove sysclk references Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 12/13] ASoC: tlv320aic32x4: Propery Set Processing Blocks Annaliese McDermond
  2019-03-19  3:37 ` [PATCH 13/13] ASoC: tlv320aic32x4: Allow 192000 Sample Rate Annaliese McDermond
  12 siblings, 0 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

mclk is not used by anything anymore.  Remove support for it.
All that information now comes from the clock tree.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 27babe48d5bc..2940cb2e5a4a 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -53,7 +53,6 @@ struct aic32x4_priv {
 	u32 micpga_routing;
 	bool swapdacs;
 	int rstn_gpio;
-	struct clk *mclk;
 	const char *mclk_name;
 
 	struct regulator *supply_ldo;
@@ -1160,12 +1159,6 @@ int aic32x4_probe(struct device *dev, struct regmap *regmap)
 		aic32x4->mclk_name = "mclk";
 	}
 
-	aic32x4->mclk = devm_clk_get(dev, "mclk");
-	if (IS_ERR(aic32x4->mclk)) {
-		dev_err(dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n");
-		return PTR_ERR(aic32x4->mclk);
-	}
-
 	ret = aic32x4_register_clocks(dev, aic32x4->mclk_name);
 	if (ret)
 		return ret;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 12/13] ASoC: tlv320aic32x4: Propery Set Processing Blocks
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (10 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 11/13] ASoC: tlv320aic32x4: Remove mclk references Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  2019-03-19 15:37   ` Mark Brown
  2019-03-19  3:37 ` [PATCH 13/13] ASoC: tlv320aic32x4: Allow 192000 Sample Rate Annaliese McDermond
  12 siblings, 1 reply; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

Different processing blocks are required for different sampling
rates and power parameters.  Set the processing blocks based
on this information.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 2940cb2e5a4a..3a42a08d2a7a 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -632,6 +632,18 @@ static int aic32x4_set_dosr(struct snd_soc_component *component, u16 dosr)
 	return 0;
 }
 
+static int aic32x4_set_processing_blocks(struct snd_soc_component *component,
+						u8 r_block, u8 p_block)
+{
+	if (r_block > 18 || p_block > 25)
+		return -EINVAL;
+
+	snd_soc_component_write(component, AIC32X4_ADCSPB, r_block);
+	snd_soc_component_write(component, AIC32X4_DACSPB, p_block);
+
+	return 0;
+}
+
 static int aic32x4_setup_clocks(struct snd_soc_component *component,
 				unsigned int sample_rate)
 {
@@ -665,16 +677,19 @@ static int aic32x4_setup_clocks(struct snd_soc_component *component,
 		adc_resource_class = 6;
 		dac_resource_class = 8;
 		dosr_increment = 8;
+		aic32x4_set_processing_blocks(component, 1, 1);
 	} else if (sample_rate <= 96000) {
 		aosr = 64;
 		adc_resource_class = 6;
 		dac_resource_class = 8;
 		dosr_increment = 4;
+		aic32x4_set_processing_blocks(component, 1, 9);
 	} else if (sample_rate == 192000) {
 		aosr = 32;
 		adc_resource_class = 3;
 		dac_resource_class = 4;
 		dosr_increment = 2;
+		aic32x4_set_processing_blocks(component, 13, 19);
 	} else {
 		dev_err(component->dev, "Sampling rate not supported\n");
 		return -EINVAL;
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 13/13] ASoC: tlv320aic32x4: Allow 192000 Sample Rate
  2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
                   ` (11 preceding siblings ...)
  2019-03-19  3:37 ` [PATCH 12/13] ASoC: tlv320aic32x4: Propery Set Processing Blocks Annaliese McDermond
@ 2019-03-19  3:37 ` Annaliese McDermond
  12 siblings, 0 replies; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19  3:37 UTC (permalink / raw)
  To: broonie, alsa-devel; +Cc: team, Annaliese McDermond

The clocking and processing blocks are now properly set up to
support 192000 sample rates.  Allow drivers to ask for that.

Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
---
 sound/soc/codecs/tlv320aic32x4.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 3a42a08d2a7a..3edf712d66e2 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -843,7 +843,7 @@ static int aic32x4_set_bias_level(struct snd_soc_component *component,
 	return 0;
 }
 
-#define AIC32X4_RATES	SNDRV_PCM_RATE_8000_96000
+#define AIC32X4_RATES	SNDRV_PCM_RATE_8000_192000
 #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \
 			 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
 
-- 
2.19.1

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 02/13] ASoC: tlv320aic32x4: Model PLL in CCF
  2019-03-19  3:37 ` [PATCH 02/13] ASoC: tlv320aic32x4: Model PLL in CCF Annaliese McDermond
@ 2019-03-19 15:26   ` Mark Brown
  0 siblings, 0 replies; 23+ messages in thread
From: Mark Brown @ 2019-03-19 15:26 UTC (permalink / raw)
  To: Annaliese McDermond; +Cc: alsa-devel, team


[-- Attachment #1.1: Type: text/plain, Size: 1436 bytes --]

On Mon, Mar 18, 2019 at 08:37:45PM -0700, Annaliese McDermond wrote:

> ---
>  sound/soc/codecs/Makefile            |   2 +-
>  sound/soc/codecs/tlv320aic32x4-clk.c | 323 +++++++++++++++++++++++++++
>  sound/soc/codecs/tlv320aic32x4.c     |  93 ++++----
>  sound/soc/codecs/tlv320aic32x4.h     |   5 +
>  4 files changed, 379 insertions(+), 44 deletions(-)

I'm not seeing any Kconfig updates which add dependencies on the clock
API or conditionally build the clock implementation only if that's been
enabled.

> +++ b/sound/soc/codecs/tlv320aic32x4-clk.c
> @@ -0,0 +1,323 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * linux/sound/soc/codecs/tlv320aic32x4-clk.c
> + *
> + * Copyright 2019 Annaliese McDermond
> + *
> + * Author: Annaliese McDermond <nh6z@nh6z.net>
> + */

Please make the entire comment a C++ comment so it looks more
intentional.  It's also better to not have the path in the header since
that's prone to bitrot, just write something in words.

> +static const struct clk_ops aic32x4_pll_ops = {
> +	.enable = clk_aic32x4_pll_enable,
> +	.disable = clk_aic32x4_pll_disable,
> +	.is_enabled = clk_aic32x4_pll_is_enabled,

These are enable and disable operations - shouldn't they be prepare and
unprepare?  The device is controlled over buses that require sleeping
but the prepare and enable operations require atomic context.

> +}
> +EXPORT_SYMBOL(aic32x4_register_clocks);

ASoC is all EXPORT_SYMBOL_GPL()...

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 04/13] ASoC: tlv320aic32x4: Model DAC/ADC dividers in CCF
  2019-03-19  3:37 ` [PATCH 04/13] ASoC: tlv320aic32x4: Model DAC/ADC dividers " Annaliese McDermond
@ 2019-03-19 15:28   ` Mark Brown
  0 siblings, 0 replies; 23+ messages in thread
From: Mark Brown @ 2019-03-19 15:28 UTC (permalink / raw)
  To: Annaliese McDermond; +Cc: alsa-devel, team


[-- Attachment #1.1: Type: text/plain, Size: 633 bytes --]

On Mon, Mar 18, 2019 at 08:37:47PM -0700, Annaliese McDermond wrote:
>     Model and manage DAC/ADC dividers as components in the Core
>     Clock Framework.  This should allow us to do some more complex
>     clock management and power control.  Also, some of the
>     on-board chip clocks can be exposed to the outside, and this
>     change will make those clocks easier to consume by other
>     parts of the kernel.
> 
>     Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>
> 
> Signed-off-by: Annaliese McDermond <nh6z@nh6z.net>

Something seems to have gone weird with indentation in the commit
message here?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 09/13] ASoC: tlv320aic32x4: Fix clock activation on bias level change
  2019-03-19  3:37 ` [PATCH 09/13] ASoC: tlv320aic32x4: Fix clock activation on bias level change Annaliese McDermond
@ 2019-03-19 15:33   ` Mark Brown
  0 siblings, 0 replies; 23+ messages in thread
From: Mark Brown @ 2019-03-19 15:33 UTC (permalink / raw)
  To: Annaliese McDermond; +Cc: alsa-devel, team


[-- Attachment #1.1: Type: text/plain, Size: 494 bytes --]

On Mon, Mar 18, 2019 at 08:37:52PM -0700, Annaliese McDermond wrote:
> The clocks are double-disabled when they are first coming up
> because they are already off when it first moves into STANDBY.
> Check if the state is already off and leave things alone if
> it is.

This looks like a bug fix for the existing code prior to the series -
changes like this should be put at the start of the series so that they
can be more easily sent as fixes without having to wait for the next
merge window.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 10/13] ASoC: tlv320aic32x4: Remove sysclk references
  2019-03-19  3:37 ` [PATCH 10/13] ASoC: tlv320aic32x4: Remove sysclk references Annaliese McDermond
@ 2019-03-19 15:37   ` Mark Brown
  2019-03-19 16:18     ` Annaliese McDermond
  0 siblings, 1 reply; 23+ messages in thread
From: Mark Brown @ 2019-03-19 15:37 UTC (permalink / raw)
  To: Annaliese McDermond; +Cc: alsa-devel, team


[-- Attachment #1.1: Type: text/plain, Size: 337 bytes --]

On Mon, Mar 18, 2019 at 08:37:53PM -0700, Annaliese McDermond wrote:

> Sysclk is not used by anything anymore.  Remove support for it.
> All that information now comes from the clock tree.

Have you checked for existing users here?  If the operation is removed
existing users will get errors, not all of them will be prepared for
that.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 12/13] ASoC: tlv320aic32x4: Propery Set Processing Blocks
  2019-03-19  3:37 ` [PATCH 12/13] ASoC: tlv320aic32x4: Propery Set Processing Blocks Annaliese McDermond
@ 2019-03-19 15:37   ` Mark Brown
  2019-03-19 16:24     ` Annaliese McDermond
  0 siblings, 1 reply; 23+ messages in thread
From: Mark Brown @ 2019-03-19 15:37 UTC (permalink / raw)
  To: Annaliese McDermond; +Cc: alsa-devel, team


[-- Attachment #1.1: Type: text/plain, Size: 299 bytes --]

On Mon, Mar 18, 2019 at 08:37:55PM -0700, Annaliese McDermond wrote:
> Different processing blocks are required for different sampling
> rates and power parameters.  Set the processing blocks based
> on this information.

Is this another bug fix or does it depend on the rest of the series
somehow?

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 10/13] ASoC: tlv320aic32x4: Remove sysclk references
  2019-03-19 15:37   ` Mark Brown
@ 2019-03-19 16:18     ` Annaliese McDermond
  2019-03-20 16:27       ` Mark Brown
  0 siblings, 1 reply; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19 16:18 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, team


> On Mar 19, 2019, at 8:37 AM, Mark Brown <broonie@kernel.org> wrote:
> 
> On Mon, Mar 18, 2019 at 08:37:53PM -0700, Annaliese McDermond wrote:
> 
>> Sysclk is not used by anything anymore.  Remove support for it.
>> All that information now comes from the clock tree.
> 
> Have you checked for existing users here?  If the operation is removed
> existing users will get errors, not all of them will be prepared for
> that.

I haven’t checked with existing users.  A better implementation may be
that we just use clk_set_rate on whatever the sysclk is to set the
upstream rate.  That way we can preserve compatibility.

> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@alsa-project.org
> https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

--
Annaliese McDermond
nh6z@nh6z.net
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 12/13] ASoC: tlv320aic32x4: Propery Set Processing Blocks
  2019-03-19 15:37   ` Mark Brown
@ 2019-03-19 16:24     ` Annaliese McDermond
  2019-03-20 16:26       ` Mark Brown
  0 siblings, 1 reply; 23+ messages in thread
From: Annaliese McDermond @ 2019-03-19 16:24 UTC (permalink / raw)
  To: Mark Brown; +Cc: alsa-devel, team



> On Mar 19, 2019, at 8:37 AM, Mark Brown <broonie@kernel.org> wrote:
> 
> On Mon, Mar 18, 2019 at 08:37:55PM -0700, Annaliese McDermond wrote:
>> Different processing blocks are required for different sampling
>> rates and power parameters.  Set the processing blocks based
>> on this information.
> 
> Is this another bug fix or does it depend on the rest of the series
> somehow?

It’s not really a bug fix.  The codec has a variety of “processing blocks”
that enable different filters (there’s an onboard FIR, Biquad, etc.) and
such.  The big thing they change with regard to how the driver is written
now is that they change the decimation filter used.  The documentation
specifies to use certain filters for certain sample rates.  This
hasn’t mattered very much in the past because the default filters
(P1 and R1) are the ones recommended for 48kHz and below.  This is
particularly important for 192kHz operation because it won’t
work with P1 and R1.  So, it’s not really a bug fix.  It’s part
of the road to enabling 192kHz operation.

--
Annaliese McDermond
nh6z@nh6z.net
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 12/13] ASoC: tlv320aic32x4: Propery Set Processing Blocks
  2019-03-19 16:24     ` Annaliese McDermond
@ 2019-03-20 16:26       ` Mark Brown
  0 siblings, 0 replies; 23+ messages in thread
From: Mark Brown @ 2019-03-20 16:26 UTC (permalink / raw)
  To: Annaliese McDermond; +Cc: alsa-devel, team


[-- Attachment #1.1: Type: text/plain, Size: 889 bytes --]

On Tue, Mar 19, 2019 at 09:24:00AM -0700, Annaliese McDermond wrote:

> It’s not really a bug fix.  The codec has a variety of “processing blocks”
> that enable different filters (there’s an onboard FIR, Biquad, etc.) and
> such.  The big thing they change with regard to how the driver is written
> now is that they change the decimation filter used.  The documentation
> specifies to use certain filters for certain sample rates.  This
> hasn’t mattered very much in the past because the default filters
> (P1 and R1) are the ones recommended for 48kHz and below.  This is
> particularly important for 192kHz operation because it won’t
> work with P1 and R1.  So, it’s not really a bug fix.  It’s part
> of the road to enabling 192kHz operation.

It does sound like a bug fix for higher sample rates (96kHz is
supported?) even if it's a fairly niche case.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 10/13] ASoC: tlv320aic32x4: Remove sysclk references
  2019-03-19 16:18     ` Annaliese McDermond
@ 2019-03-20 16:27       ` Mark Brown
  0 siblings, 0 replies; 23+ messages in thread
From: Mark Brown @ 2019-03-20 16:27 UTC (permalink / raw)
  To: Annaliese McDermond; +Cc: alsa-devel, team


[-- Attachment #1.1: Type: text/plain, Size: 478 bytes --]

On Tue, Mar 19, 2019 at 09:18:01AM -0700, Annaliese McDermond wrote:

> > Have you checked for existing users here?  If the operation is removed
> > existing users will get errors, not all of them will be prepared for
> > that.

> I haven’t checked with existing users.  A better implementation may be
> that we just use clk_set_rate on whatever the sysclk is to set the
> upstream rate.  That way we can preserve compatibility.

Yes, that'd be the simplest thing.

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2019-03-20 16:27 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-03-19  3:37 [PATCH 00/13] ASoC: tlv320aic32x4: Rework Clock Setting Annaliese McDermond
2019-03-19  3:37 ` [PATCH 01/13] ASoC: tlv320aic32x4: Break out clock setting into separate function Annaliese McDermond
2019-03-19  3:37 ` [PATCH 02/13] ASoC: tlv320aic32x4: Model PLL in CCF Annaliese McDermond
2019-03-19 15:26   ` Mark Brown
2019-03-19  3:37 ` [PATCH 03/13] ASoC: tlv320aic32x4: Model CODEC_CLKIN " Annaliese McDermond
2019-03-19  3:37 ` [PATCH 04/13] ASoC: tlv320aic32x4: Model DAC/ADC dividers " Annaliese McDermond
2019-03-19 15:28   ` Mark Brown
2019-03-19  3:37 ` [PATCH 05/13] ASoC: tlv320aic32x4: Model BDIV divider " Annaliese McDermond
2019-03-19  3:37 ` [PATCH 06/13] ASoC: tlv320aic32x4: Control clock gating with CCF Annaliese McDermond
2019-03-19  3:37 ` [PATCH 07/13] ASoC: tlv320aic32x4: Move aosr and dosr setting to separate functions Annaliese McDermond
2019-03-19  3:37 ` [PATCH 08/13] ASoC: tlv320aic32x4: Dynamically Determine Clocking Annaliese McDermond
2019-03-19  3:37 ` [PATCH 09/13] ASoC: tlv320aic32x4: Fix clock activation on bias level change Annaliese McDermond
2019-03-19 15:33   ` Mark Brown
2019-03-19  3:37 ` [PATCH 10/13] ASoC: tlv320aic32x4: Remove sysclk references Annaliese McDermond
2019-03-19 15:37   ` Mark Brown
2019-03-19 16:18     ` Annaliese McDermond
2019-03-20 16:27       ` Mark Brown
2019-03-19  3:37 ` [PATCH 11/13] ASoC: tlv320aic32x4: Remove mclk references Annaliese McDermond
2019-03-19  3:37 ` [PATCH 12/13] ASoC: tlv320aic32x4: Propery Set Processing Blocks Annaliese McDermond
2019-03-19 15:37   ` Mark Brown
2019-03-19 16:24     ` Annaliese McDermond
2019-03-20 16:26       ` Mark Brown
2019-03-19  3:37 ` [PATCH 13/13] ASoC: tlv320aic32x4: Allow 192000 Sample Rate Annaliese McDermond

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.