From: Zidan Wang <zidan.wang@freescale.com> To: <broonie@kernel.org> Cc: <lgirdwood@gmail.com>, <perex@perex.cz>, <tiwai@suse.de>, <lars@metafoo.de>, <ckeepax@opensource.wolfsonmicro.com>, <patches@opensource.wolfsonmicro.com>, <alsa-devel@alsa-project.org>, <linux-kernel@vger.kernel.org>, Zidan Wang <b50113@freescale.com> Subject: [alsa-devel][PATCH v2 2/2] ASoC: wm8960: Let wm8960 driver configure its bit clock and frame clock Date: Wed, 7 Jan 2015 15:31:45 +0800 [thread overview] Message-ID: <1420615905-4078-2-git-send-email-zidan.wang@freescale.com> (raw) In-Reply-To: <1420615905-4078-1-git-send-email-zidan.wang@freescale.com> From: Zidan Wang <b50113@freescale.com> wm8960 codec driver missing configure its bit clock and frame clock, so add support for it. It will calculate a appropriate frequency dividing ratio according to the system clock, bit clock and frame clock, then set the corresponding registers. Signed-off-by: Zidan Wang <b50113@freescale.com> --- sound/soc/codecs/wm8960.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index fd25973..aba6bbf 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -127,6 +127,8 @@ struct wm8960_priv { struct snd_soc_dapm_widget *out3; bool deemph; int playback_fs; + int bclk; + int sysclk; struct wm8960_data pdata; }; @@ -563,6 +565,68 @@ static struct { { 8000, 5 }, }; +/* Multiply 256 for internal 256 div */ +static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; + +/* Multiply 10 to eliminate decimials */ +static const int bclk_divs[] = { + 10, 15, 20, 30, 40, 55, 60, 80, 110, + 120, 160, 220, 240, 320, 320, 320 +}; + +static void wm8960_configure_clocking(struct snd_soc_codec *codec, + int stream, int lrclk) +{ + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); + u16 iface2 = snd_soc_read(codec, WM8960_IFACE2); + int i, j; + + if (!(iface1 & (1<<6))) { + dev_dbg(codec->dev, + "Codec is slave mode, no need to configure clock\n"); + return; + } + + if (!wm8960->sysclk) { + dev_dbg(codec->dev, "No SYSCLK configured\n"); + return; + } + + if (!wm8960->bclk || !lrclk) { + dev_dbg(codec->dev, "No audio clocks configured\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) { + if (wm8960->sysclk == lrclk * dac_divs[i]) { + for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) { + if (wm8960->sysclk == wm8960->bclk * + bclk_divs[j] / 10) { + goto config_clock; + } + } + } + } + + dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk); + return; + +config_clock: + /* configure frame clock. If ADCLRC configure as GPIO pin, DACLRC + * pin is used as a frame clock for ADCs and DACs. + */ + if (iface2 & (1<<6)) + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); + else if (SNDRV_PCM_STREAM_PLAYBACK == stream) + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); + else if (SNDRV_PCM_STREAM_CAPTURE == stream) + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6); + + /* configure bit clock */ + snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j); +} + static int wm8960_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -572,6 +636,10 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; int i; + wm8960->bclk = snd_soc_params_to_bclk(params); + if (params_channels(params) == 1) + wm8960->bclk *= 2; + /* bit size */ switch (params_width(params)) { case 16: @@ -602,6 +670,10 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, /* set iface */ snd_soc_write(codec, WM8960_IFACE1, iface); + + wm8960_configure_clocking(codec, substream->stream, + params_rate(params)); + return 0; } @@ -950,6 +1022,30 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, return wm8960->set_bias_level(codec, level); } +static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + + switch (clk_id) { + case WM8960_SYSCLK_MCLK: + snd_soc_update_bits(codec, WM8960_CLOCK1, + 0x1, WM8960_SYSCLK_MCLK); + break; + case WM8960_SYSCLK_PLL: + snd_soc_update_bits(codec, WM8960_CLOCK1, + 0x1, WM8960_SYSCLK_PLL); + break; + default: + return -EINVAL; + } + + wm8960->sysclk = freq; + + return 0; +} + #define WM8960_RATES SNDRV_PCM_RATE_8000_48000 #define WM8960_FORMATS \ @@ -962,6 +1058,7 @@ static const struct snd_soc_dai_ops wm8960_dai_ops = { .set_fmt = wm8960_set_dai_fmt, .set_clkdiv = wm8960_set_dai_clkdiv, .set_pll = wm8960_set_dai_pll, + .set_sysclk = wm8960_set_dai_sysclk, }; static struct snd_soc_dai_driver wm8960_dai = { -- 1.9.1
WARNING: multiple messages have this Message-ID (diff)
From: Zidan Wang <zidan.wang@freescale.com> To: broonie@kernel.org Cc: lgirdwood@gmail.com, perex@perex.cz, tiwai@suse.de, lars@metafoo.de, ckeepax@opensource.wolfsonmicro.com, patches@opensource.wolfsonmicro.com, alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org, Zidan Wang <b50113@freescale.com> Subject: [alsa-devel][PATCH v2 2/2] ASoC: wm8960: Let wm8960 driver configure its bit clock and frame clock Date: Wed, 7 Jan 2015 15:31:45 +0800 [thread overview] Message-ID: <1420615905-4078-2-git-send-email-zidan.wang@freescale.com> (raw) In-Reply-To: <1420615905-4078-1-git-send-email-zidan.wang@freescale.com> From: Zidan Wang <b50113@freescale.com> wm8960 codec driver missing configure its bit clock and frame clock, so add support for it. It will calculate a appropriate frequency dividing ratio according to the system clock, bit clock and frame clock, then set the corresponding registers. Signed-off-by: Zidan Wang <b50113@freescale.com> --- sound/soc/codecs/wm8960.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index fd25973..aba6bbf 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -127,6 +127,8 @@ struct wm8960_priv { struct snd_soc_dapm_widget *out3; bool deemph; int playback_fs; + int bclk; + int sysclk; struct wm8960_data pdata; }; @@ -563,6 +565,68 @@ static struct { { 8000, 5 }, }; +/* Multiply 256 for internal 256 div */ +static const int dac_divs[] = { 256, 384, 512, 768, 1024, 1408, 1536 }; + +/* Multiply 10 to eliminate decimials */ +static const int bclk_divs[] = { + 10, 15, 20, 30, 40, 55, 60, 80, 110, + 120, 160, 220, 240, 320, 320, 320 +}; + +static void wm8960_configure_clocking(struct snd_soc_codec *codec, + int stream, int lrclk) +{ + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + u16 iface1 = snd_soc_read(codec, WM8960_IFACE1); + u16 iface2 = snd_soc_read(codec, WM8960_IFACE2); + int i, j; + + if (!(iface1 & (1<<6))) { + dev_dbg(codec->dev, + "Codec is slave mode, no need to configure clock\n"); + return; + } + + if (!wm8960->sysclk) { + dev_dbg(codec->dev, "No SYSCLK configured\n"); + return; + } + + if (!wm8960->bclk || !lrclk) { + dev_dbg(codec->dev, "No audio clocks configured\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(dac_divs); ++i) { + if (wm8960->sysclk == lrclk * dac_divs[i]) { + for (j = 0; j < ARRAY_SIZE(bclk_divs); ++j) { + if (wm8960->sysclk == wm8960->bclk * + bclk_divs[j] / 10) { + goto config_clock; + } + } + } + } + + dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk); + return; + +config_clock: + /* configure frame clock. If ADCLRC configure as GPIO pin, DACLRC + * pin is used as a frame clock for ADCs and DACs. + */ + if (iface2 & (1<<6)) + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); + else if (SNDRV_PCM_STREAM_PLAYBACK == stream) + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3); + else if (SNDRV_PCM_STREAM_CAPTURE == stream) + snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 6, i << 6); + + /* configure bit clock */ + snd_soc_update_bits(codec, WM8960_CLOCK2, 0xf, j); +} + static int wm8960_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -572,6 +636,10 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; int i; + wm8960->bclk = snd_soc_params_to_bclk(params); + if (params_channels(params) == 1) + wm8960->bclk *= 2; + /* bit size */ switch (params_width(params)) { case 16: @@ -602,6 +670,10 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, /* set iface */ snd_soc_write(codec, WM8960_IFACE1, iface); + + wm8960_configure_clocking(codec, substream->stream, + params_rate(params)); + return 0; } @@ -950,6 +1022,30 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, return wm8960->set_bias_level(codec, level); } +static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); + + switch (clk_id) { + case WM8960_SYSCLK_MCLK: + snd_soc_update_bits(codec, WM8960_CLOCK1, + 0x1, WM8960_SYSCLK_MCLK); + break; + case WM8960_SYSCLK_PLL: + snd_soc_update_bits(codec, WM8960_CLOCK1, + 0x1, WM8960_SYSCLK_PLL); + break; + default: + return -EINVAL; + } + + wm8960->sysclk = freq; + + return 0; +} + #define WM8960_RATES SNDRV_PCM_RATE_8000_48000 #define WM8960_FORMATS \ @@ -962,6 +1058,7 @@ static const struct snd_soc_dai_ops wm8960_dai_ops = { .set_fmt = wm8960_set_dai_fmt, .set_clkdiv = wm8960_set_dai_clkdiv, .set_pll = wm8960_set_dai_pll, + .set_sysclk = wm8960_set_dai_sysclk, }; static struct snd_soc_dai_driver wm8960_dai = { -- 1.9.1
next prev parent reply other threads:[~2015-01-07 8:04 UTC|newest] Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top 2015-01-07 7:31 [alsa-devel][PATCH v2 1/2] ASoC: wm8960: Let wm8960 codec driver manage its own MCLK Zidan Wang 2015-01-07 7:31 ` Zidan Wang 2015-01-07 7:31 ` Zidan Wang [this message] 2015-01-07 7:31 ` [alsa-devel][PATCH v2 2/2] ASoC: wm8960: Let wm8960 driver configure its bit clock and frame clock Zidan Wang 2015-01-14 19:27 ` Mark Brown 2015-01-15 13:34 ` Zidan Wang 2015-01-15 13:34 ` [PATCH " Zidan Wang 2017-04-03 13:16 ` [alsa-devel][PATCH " Daniel Baluta 2017-04-03 13:16 ` [PATCH " Daniel Baluta 2017-04-03 13:34 ` [alsa-devel][PATCH " Charles Keepax 2017-04-03 13:34 ` [PATCH " Charles Keepax 2017-04-03 13:39 ` [alsa-devel][PATCH " Daniel Baluta 2017-04-03 13:39 ` [PATCH " Daniel Baluta 2017-04-03 13:54 ` [alsa-devel][PATCH " Charles Keepax 2017-04-03 13:54 ` [PATCH " Charles Keepax 2017-04-04 7:55 ` [alsa-devel][PATCH " Daniel Baluta 2017-04-04 7:55 ` [PATCH " Daniel Baluta 2017-04-04 8:55 ` [alsa-devel][PATCH " Charles Keepax 2017-04-04 8:55 ` [PATCH " Charles Keepax 2015-01-14 19:19 ` [alsa-devel][PATCH v2 1/2] ASoC: wm8960: Let wm8960 codec driver manage its own MCLK Mark Brown 2015-01-14 19:19 ` [PATCH " Mark Brown
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1420615905-4078-2-git-send-email-zidan.wang@freescale.com \ --to=zidan.wang@freescale.com \ --cc=alsa-devel@alsa-project.org \ --cc=b50113@freescale.com \ --cc=broonie@kernel.org \ --cc=ckeepax@opensource.wolfsonmicro.com \ --cc=lars@metafoo.de \ --cc=lgirdwood@gmail.com \ --cc=linux-kernel@vger.kernel.org \ --cc=patches@opensource.wolfsonmicro.com \ --cc=perex@perex.cz \ --cc=tiwai@suse.de \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
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.