wm8960 codec driver missing configure its bit clock and frame clock for codec
master mode, 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 <[email protected]>
---
sound/soc/codecs/wm8960.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 101 insertions(+)
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 6fa832b..b072501 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,72 @@ 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,
+ bool tx, 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);
+ u32 sysclk;
+ 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) {
+ sysclk = wm8960->bclk * bclk_divs[j] / 10;
+ if (wm8960->sysclk == sysclk)
+ break;
+ }
+ if(j != ARRAY_SIZE(bclk_divs))
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(dac_divs)) {
+ dev_err(codec->dev, "Unsupported sysclk %d\n", wm8960->sysclk);
+ return;
+ }
+
+ /*
+ * 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 (tx)
+ snd_soc_update_bits(codec, WM8960_CLOCK1, 0x7 << 3, i << 3);
+ else if (!tx)
+ 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)
@@ -570,8 +638,13 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3;
+ bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
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 +675,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
/* set iface */
snd_soc_write(codec, WM8960_IFACE1, iface);
+
+ wm8960_configure_clocking(codec, tx, params_rate(params));
+
return 0;
}
@@ -946,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 \
@@ -958,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
According to referance manual, right justify mode can't
support 32 bit word length.
Signed-off-by: Zidan Wang <[email protected]>
---
sound/soc/codecs/wm8960.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index b072501..2559e31 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -655,6 +655,12 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream,
case 24:
iface |= 0x0008;
break;
+ case 32:
+ /* right justify mode does not support 32 word length */
+ if ((iface & 0x3) != 0) {
+ iface |= 0x000c;
+ break;
+ }
default:
dev_err(codec->dev, "unsupported width %d\n",
params_width(params));
@@ -1050,7 +1056,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id,
#define WM8960_FORMATS \
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static const struct snd_soc_dai_ops wm8960_dai_ops = {
.hw_params = wm8960_hw_params,
--
1.9.1
It should be "RINPUT3" instead of "LINPUT3" route to "Right Input
Mixer".
Signed-off-by: Zidan Wang <[email protected]>
---
sound/soc/codecs/wm8960.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 2559e31..4ab1607 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -397,7 +397,7 @@ static const struct snd_soc_dapm_route audio_paths[] = {
{ "Right Input Mixer", "Boost Switch", "Right Boost Mixer", },
{ "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */
{ "Right Input Mixer", NULL, "RINPUT2" },
- { "Right Input Mixer", NULL, "LINPUT3" },
+ { "Right Input Mixer", NULL, "RINPUT3" },
{ "Left ADC", NULL, "Left Input Mixer" },
{ "Right ADC", NULL, "Right Input Mixer" },
--
1.9.1
According to the RM of wm8958, BCLK DIV 348 doesn't exist, correct it
to 384.
Signed-off-by: Zidan Wang <[email protected]>
---
sound/soc/codecs/wm8994.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 2d32b54..33bf663 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2752,7 +2752,7 @@ static struct {
};
static int fs_ratios[] = {
- 64, 128, 192, 256, 348, 512, 768, 1024, 1408, 1536
+ 64, 128, 192, 256, 384, 512, 768, 1024, 1408, 1536
};
static int bclk_divs[] = {
--
1.9.1
On Tue, May 12, 2015 at 02:58:36PM +0800, Zidan Wang wrote:
> It should be "RINPUT3" instead of "LINPUT3" route to "Right Input
> Mixer".
>
> Signed-off-by: Zidan Wang <[email protected]>
> ---
Acked-by: Charles Keepax <[email protected]>
Better to put bug fixes like this at the start of a series if
possible.
Thanks,
Charles
On Tue, May 12, 2015 at 02:58:50PM +0800, Zidan Wang wrote:
> According to the RM of wm8958, BCLK DIV 348 doesn't exist, correct it
> to 384.
>
> Signed-off-by: Zidan Wang <[email protected]>
> ---
Acked-by: Charles Keepax <[email protected]>
Thanks,
Charles
On Tue, May 12, 2015 at 02:58:21PM +0800, Zidan Wang wrote:
> According to referance manual, right justify mode can't
> support 32 bit word length.
>
> Signed-off-by: Zidan Wang <[email protected]>
> ---
Acked-by: Charles Keepax <[email protected]>
Thanks,
Charles
On Tue, May 12, 2015 at 02:58:08PM +0800, Zidan Wang wrote:
> wm8960 codec driver missing configure its bit clock and frame clock for codec
> master mode, 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.
Applied all, thanks.