Fixes for XU4 patch

This commit is contained in:
Igor Pecovnik 2018-05-25 18:09:44 +02:00
parent 48c71e6d83
commit 56aaae211d

View File

@ -99337,419 +99337,3 @@ diff -ruN b/sound/soc/samsung/Kconfig a/sound/soc/samsung/Kconfig
help
Say Y here to enable audio support for the Odroid XU3/XU4.
diff -ruN b/sound/soc/samsung/odroid.c a/sound/soc/samsung/odroid.c
--- b/sound/soc/samsung/odroid.c 2018-03-27 10:17:59.846849052 +0200
+++ a/sound/soc/samsung/odroid.c 2018-03-27 10:06:54.366190706 +0200
@@ -18,75 +18,321 @@
struct odroid_priv {
struct snd_soc_card card;
struct snd_soc_dai_link dai_link;
-
- struct clk *clk_i2s_bus;
- struct clk *sclk_i2s;
};
-static int odroid_card_startup(struct snd_pcm_substream *substream)
+static int set_audio_clock_heirachy(struct device *card_dev);
+
+/*
+ * The initial rate that EPLL will be set to. This is the smallest multiple (4)
+ * of the desired master clock frequency 256 * FS for FS = 44.1khz that can
+ * be generated on both the 5250 and 5420 SoCs.
+ */
+static int set_audss_pll_rate(struct device *card_dev, unsigned long epll,
+ unsigned long sclk, unsigned long rclk)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
+ int ret;
+ struct clk *fout_epll;
+ struct clk *dout_srp, *dout_aud_bus;
+ unsigned long clk_margin=500;
+
+ ret = set_audio_clock_heirachy(card_dev);
+ if (ret) {
+ dev_err(card_dev, "failed to set up clock hierarchy (%d)\n",
+ ret);
+ }
+ fout_epll = devm_clk_get(card_dev, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ dev_err(card_dev, "%s: failed to get fout_epll\n", __func__);
+ return PTR_ERR(fout_epll);
+ }
+ dout_srp = devm_clk_get(card_dev, "dout_srp");
+ if (IS_ERR(dout_srp)) {
+ dev_err(card_dev, "%s: failed to get dout_srp\n", __func__);
+ goto out1;
+ }
+ dout_aud_bus = devm_clk_get(card_dev, "dout_aud_bus");
+ if (IS_ERR(dout_aud_bus)) {
+ dev_err(card_dev, "%s: failed to get dout_aud_bus\n", __func__);
+ goto out2;
+ }
+
+ ret = clk_set_rate(fout_epll, epll);
+ if (ret < 0) {
+ dev_err(card_dev, "failed to clk_set_rate of fout_epll for audio\n");
+ goto out3;
+ }
+ ret = clk_set_rate(dout_srp, sclk+clk_margin);
+ if (ret < 0) {
+ dev_err(card_dev, "failed to clk_set_rate of dout_srp for audio\n");
+ goto out3;
+ }
+ ret = clk_set_rate(dout_aud_bus, rclk+clk_margin);
+ if (ret < 0) {
+ dev_err(card_dev, "failed to clk_set_rate of dout_aud_bus for audio\n");
+ goto out3;
+ }
+ dev_dbg(card_dev,"%s[%d] : epll=%ld\n",__func__,__LINE__,clk_get_rate(fout_epll));
+ dev_dbg(card_dev,"%s[%d] : dout_srp=%ld\n",__func__,__LINE__,clk_get_rate(dout_srp));
+ dev_dbg(card_dev,"%s[%d] : dout_bus=%ld\n",__func__,__LINE__,clk_get_rate(dout_aud_bus));
+out3:
+ clk_put(dout_aud_bus);
+out2:
+ clk_put(dout_srp);
+out1:
+ clk_put(fout_epll);
- snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
return 0;
}
+/* Audio clock settings are belonged to board specific part. Every
+ * board can set audio source clock setting which is matched with H/W
+ * like this function-'set_audio_clock_heirachy'.
+ */
+static int set_audio_clock_heirachy(struct device *card_dev)
+{
+ struct clk *fout_epll, *mout_sclk_epll;
+ struct clk *mout_mau_epll, *mout_mau_epll_user;
+ struct clk *mout_audss, *mout_i2s;
+ struct clk *mau_epll;
+ int ret = 0;
+
+ fout_epll = devm_clk_get(card_dev, "fout_epll");
+ if (IS_ERR(fout_epll)) {
+ dev_err(card_dev, "%s: Cannot find fout_epll.\n",
+ __func__);
+ return -EINVAL;
+ }
+ clk_prepare_enable(fout_epll);
+
+ mout_sclk_epll = devm_clk_get(card_dev, "mout_sclk_epll");
+ if (IS_ERR(mout_sclk_epll)) {
+ dev_err(card_dev, "%s: Cannot find mout_sclk_epll.\n", __func__);
+ ret = -EINVAL;
+ goto out1;
+ }
+ clk_prepare_enable(mout_sclk_epll);
+
+ mout_mau_epll = devm_clk_get(card_dev, "mout_mau_epll");
+ if (IS_ERR(mout_mau_epll)) {
+ dev_err(card_dev,
+ "%s: Cannot find mout_mau_epll clocks.\n", __func__);
+ ret = -EINVAL;
+ goto out2;
+ }
+ clk_prepare_enable(mout_mau_epll);
+
+ mout_mau_epll_user = devm_clk_get(card_dev, "mout_mau_epll_user");
+ if (IS_ERR(mout_mau_epll_user)) {
+ dev_err(card_dev,
+ "%s: Cannot find mout_mau_epll_user clocks.\n", __func__);
+ ret = -EINVAL;
+ goto out3;
+ }
+ clk_prepare_enable(mout_mau_epll_user);
+
+ mout_audss = devm_clk_get(card_dev, "mout_audss");
+ if (IS_ERR(mout_audss)) {
+ dev_err(card_dev,
+ "%s: Cannot find mout_audss clocks.\n", __func__);
+ ret = -EINVAL;
+ goto out4;
+ }
+ clk_prepare_enable(mout_audss);
+
+ mout_i2s = devm_clk_get(card_dev, "mout_i2s");
+ if (IS_ERR(mout_i2s)) {
+ dev_err(card_dev,
+ "%s: Cannot find mout_i2s clocks.\n", __func__);
+ ret = -EINVAL;
+ goto out5;
+ }
+ clk_prepare_enable(mout_i2s);
+
+ mau_epll = devm_clk_get(card_dev, "mau_epll_clk");
+ if (IS_ERR(mau_epll)) {
+ dev_err(card_dev,
+ "%s: Cannot find mau_epll clocks.\n", __func__);
+ ret = -EINVAL;
+ goto out6;
+ }
+ clk_prepare_enable(mau_epll);
+
+ /* Set audio clock hierarchy for S/PDIF */
+ ret = clk_set_parent(mout_sclk_epll, fout_epll);
+ if (ret < 0) {
+ dev_err(card_dev, "Failed to set parent of epll.\n");
+ goto out7;
+ }
+ ret = clk_set_parent(mout_mau_epll, mout_sclk_epll);
+ if (ret < 0) {
+ dev_err(card_dev, "Failed to set parent of mout_mau_epll.\n");
+ goto out7;
+ }
+ ret = clk_set_parent(mout_mau_epll_user, mout_mau_epll);
+ if (ret < 0) {
+ dev_err(card_dev, "Failed to set parent of epll.\n");
+ goto out7;
+ }
+ ret = clk_set_parent(mout_audss, mout_mau_epll_user);
+ if (ret < 0) {
+ dev_err(card_dev, "Failed to set parent of audss.\n");
+ goto out7;
+ }
+ ret = clk_set_parent(mout_i2s, mout_audss);
+ if (ret < 0) {
+ dev_err(card_dev, "Failed to set parent of mout i2s.\n");
+ goto out7;
+ }
+out7:
+ clk_put(mau_epll);
+out6:
+ clk_put(mout_i2s);
+out5:
+ clk_put(mout_audss);
+out4:
+ clk_put(mout_mau_epll_user);
+out3:
+ clk_put(mout_mau_epll);
+out2:
+ clk_put(mout_sclk_epll);
+out1:
+ clk_put(fout_epll);
+
+ return ret;
+}
+
static int odroid_card_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct odroid_priv *priv = snd_soc_card_get_drvdata(rtd->card);
- unsigned int pll_freq, rclk_freq;
- int ret;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int bfs, psr, rfs, ret, div=4;
+ unsigned long rclk, sclk;
+ unsigned long pll;
+ struct device *card_dev = substream->pcm->card->dev;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_U24_LE:
+ case SNDRV_PCM_FORMAT_S24_LE:
+ bfs = 48;
+ break;
+ case SNDRV_PCM_FORMAT_U16_LE:
+ case SNDRV_PCM_FORMAT_S16_LE:
+ bfs = 32;
+ break;
+ default:
+ return -EINVAL;
+ }
switch (params_rate(params)) {
+ case 16000:
+ case 22050:
+ case 24000:
case 32000:
- case 64000:
- pll_freq = 131072006U;
- break;
case 44100:
- case 88200:
- case 176400:
- pll_freq = 180633609U;
- break;
case 48000:
+ case 88200:
case 96000:
- case 192000:
- pll_freq = 196608001U;
+ if (bfs == 48)
+ rfs = 384;
+ else
+ rfs = 256;
+ break;
+ case 64000:
+ rfs = 384;
+ break;
+ case 8000:
+ case 11025:
+ case 12000:
+ if (bfs == 48)
+ rfs = 768;
+ else
+ rfs = 512;
break;
default:
return -EINVAL;
}
- ret = clk_set_rate(priv->clk_i2s_bus, pll_freq / 2 + 1);
+ rclk = params_rate(params) * rfs;
+
+ switch (rclk) {
+ case 4096000:
+ case 5644800:
+ case 6144000:
+ case 8467200:
+ case 9216000:
+ psr = 8;
+ break;
+ case 8192000:
+ case 11289600:
+ case 12288000:
+ case 16934400:
+ case 18432000:
+ psr = 4;
+ break;
+ case 22579200:
+ case 24576000:
+ case 33868800:
+ case 36864000:
+ psr = 2;
+ break;
+ case 67737600:
+ case 73728000:
+ psr = 1;
+ break;
+ default:
+ dev_err(card_dev, "rclk = %lu is not yet supported!\n", rclk);
+ return -EINVAL;
+ }
+
+ dev_dbg(card_dev,"%s[%d]: rate=%d, bfs=%d, rfs=%d, psr=%d \n",
+ __func__,__LINE__, params_rate(params), bfs, rfs, psr);
+
+ sclk = rclk * psr;
+ pll = sclk * div;
+ dev_dbg(card_dev,"%s[%d]: rclk=%ld, sclk=%ld, pll=%ld\n",
+ __func__,__LINE__, rclk, sclk, pll);
+
+ ret = set_audss_pll_rate(card_dev, pll, sclk, rclk);
if (ret < 0)
return ret;
- /*
- * We add 1 to the rclk_freq value in order to avoid too low clock
- * frequency values due to the EPLL output frequency not being exact
- * multiple of the audio sampling rate.
- */
- rclk_freq = params_rate(params) * 256 + 1;
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBS_CFS);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_IN);
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
- ret = clk_set_rate(priv->sclk_i2s, rclk_freq);
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK,
+ 0, MOD_OPCLK_PCLK);
if (ret < 0)
return ret;
- if (rtd->num_codecs > 1) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[1];
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
+ rclk, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
- ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk_freq,
- SND_SOC_CLOCK_IN);
- if (ret < 0)
- return ret;
- }
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
+ rfs, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_clkdiv(cpu_dai, SAMSUNG_I2S_DIV_BCLK, bfs);
+ if (ret < 0)
+ return ret;
return 0;
}
static const struct snd_soc_ops odroid_card_ops = {
- .startup = odroid_card_startup,
.hw_params = odroid_card_hw_params,
};
@@ -117,7 +363,6 @@
card = &priv->card;
card->dev = dev;
-
card->owner = THIS_MODULE;
card->fully_routed = true;
@@ -168,32 +413,22 @@
link->name = "Primary";
link->stream_name = link->name;
-
- priv->sclk_i2s = of_clk_get_by_name(link->cpu_of_node, "i2s_opclk1");
- if (IS_ERR(priv->sclk_i2s)) {
- ret = PTR_ERR(priv->sclk_i2s);
- goto err_put_i2s_n;
- }
-
- priv->clk_i2s_bus = of_clk_get_by_name(link->cpu_of_node, "iis");
- if (IS_ERR(priv->clk_i2s_bus)) {
- ret = PTR_ERR(priv->clk_i2s_bus);
- goto err_put_sclk;
- }
-
ret = devm_snd_soc_register_card(dev, card);
if (ret < 0) {
dev_err(dev, "snd_soc_register_card() failed: %d\n", ret);
goto err_put_clk_i2s;
}
+ ret = set_audio_clock_heirachy(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set up clock hierarchy (%d)\n",
+ ret);
+ snd_soc_unregister_card(card);
+ }
+
return 0;
err_put_clk_i2s:
- clk_put(priv->clk_i2s_bus);
-err_put_sclk:
- clk_put(priv->sclk_i2s);
-err_put_i2s_n:
of_node_put(link->cpu_of_node);
err_put_codec_n:
odroid_put_codec_of_nodes(link);
@@ -206,8 +441,6 @@
of_node_put(priv->dai_link.cpu_of_node);
odroid_put_codec_of_nodes(&priv->dai_link);
- clk_put(priv->sclk_i2s);
- clk_put(priv->clk_i2s_bus);
return 0;
}