[alsa-devel] [RFC PATCH] ASoC: pcm512x: enable set_sysclk callback

Pierre-Louis Bossart pierre-louis.bossart at linux.intel.com
Fri Jun 1 23:26:43 CEST 2018


For codec master mode, the current pcm512x code relies on the clock API.

Simple boards such as Hifiberry DAC+ PRO rely on 2 local oscillators
to generate 44.1 or 48kHz multiples, with the clock selection being
handled by the machine driver toggling GPIOS.

The RaspberryPi kernel exposes a "hifiberry,dacpro-clk" clock driver
which does nothing but tell the codec driver what rate is set by the
machine driver [1][2]

This patch suggests an alternate fallback solution to let the codec
driver know what the sysclk is based on the existing .set_sysclk
callback.

[1] https://github.com/raspberrypi/linux/blob/rpi-4.14.y/sound/soc/bcm/hifiberry_dacplus.c
[2] https://github.com/raspberrypi/linux/blob/rpi-4.14.y/drivers/clk/clk-hifiberry-dacpro.c

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
---
 sound/soc/codecs/pcm512x.c | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index f0f2d4fd3769..8d6c173c1e25 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -40,6 +40,7 @@ static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = {
 struct pcm512x_priv {
 	struct regmap *regmap;
 	struct clk *sclk;
+	int sysclk;
 	struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES];
 	struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES];
 	int fmt;
@@ -519,6 +520,29 @@ static int pcm512x_hw_rule_rate(struct snd_pcm_hw_params *params,
 				   ARRAY_SIZE(ranges), ranges, 0);
 }
 
+static int sclk_get_rate(struct pcm512x_priv *pcm512x)
+{
+	if (!IS_ERR(pcm512x->sclk))
+		return clk_get_rate(pcm512x->sclk);
+	else
+		return pcm512x->sysclk;
+}
+
+static int pcm512x_set_sysclk(struct snd_soc_dai *dai,
+			      int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_component *component = dai->component;
+	struct pcm512x_priv *pcm512x = snd_soc_component_get_drvdata(component);
+
+	switch (freq) {
+	case 22579200:
+	case 24576000:
+		pcm512x->sysclk = freq;
+		return 0;
+	}
+	return -EINVAL;
+}
+
 static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
 				      struct snd_soc_dai *dai)
 {
@@ -528,7 +552,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_constraint_ratnums *constraints_no_pll;
 	struct snd_ratnum *rats_no_pll;
 
-	if (IS_ERR(pcm512x->sclk)) {
+	if (IS_ERR(pcm512x->sclk) && !pcm512x->sysclk) {
 		dev_err(dev, "Need SCLK for master mode: %ld\n",
 			PTR_ERR(pcm512x->sclk));
 		return PTR_ERR(pcm512x->sclk);
@@ -551,7 +575,7 @@ static int pcm512x_dai_startup_master(struct snd_pcm_substream *substream,
 	if (!rats_no_pll)
 		return -ENOMEM;
 	constraints_no_pll->rats = rats_no_pll;
-	rats_no_pll->num = clk_get_rate(pcm512x->sclk) / 64;
+	rats_no_pll->num = sclk_get_rate(pcm512x) / 64;
 	rats_no_pll->den_min = 1;
 	rats_no_pll->den_max = 128;
 	rats_no_pll->den_step = 1;
@@ -858,7 +882,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
 	}
 
 	if (!pcm512x->pll_out) {
-		sck_rate = clk_get_rate(pcm512x->sclk);
+		sck_rate = sclk_get_rate(pcm512x);
 		bclk_div = params->rate_den * 64 / lrclk_div;
 		bclk_rate = DIV_ROUND_CLOSEST(sck_rate, bclk_div);
 
@@ -875,7 +899,7 @@ static int pcm512x_set_dividers(struct snd_soc_dai *dai,
 		}
 		bclk_rate = ret;
 
-		pllin_rate = clk_get_rate(pcm512x->sclk);
+		pllin_rate = sclk_get_rate(pcm512x);
 
 		sck_rate = pcm512x_find_sck(dai, bclk_rate);
 		if (!sck_rate)
@@ -1323,6 +1347,7 @@ static const struct snd_soc_dai_ops pcm512x_dai_ops = {
 	.startup = pcm512x_dai_startup,
 	.hw_params = pcm512x_hw_params,
 	.set_fmt = pcm512x_set_fmt,
+	.set_sysclk = pcm512x_set_sysclk,
 };
 
 static struct snd_soc_dai_driver pcm512x_dai = {
-- 
2.14.1



More information about the Alsa-devel mailing list