@@ -199,6 +199,8 @@ config SND_SOC_ARNDALE_RT5631_ALC5631
depends on I2C
select SND_SAMSUNG_I2S
select SND_SOC_RT5631
+ select MFD_WM8994
+ select SND_SOC_WM8994
config SND_SOC_SAMSUNG_TM2_WM5110
tristate "SoC I2S Audio support for WM5110 on TM2 board"
@@ -14,10 +14,11 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include "../codecs/wm8994.h"
#include "i2s.h"
-static int arndale_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+static int arndale_rt5631_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
@@ -47,13 +48,45 @@ static int arndale_hw_params(struct snd_pcm_substream *substream,
return 0;
}
-static struct snd_soc_ops arndale_ops = {
- .hw_params = arndale_hw_params,
+static struct snd_soc_ops arndale_rt5631_ops = {
+ .hw_params = arndale_rt5631_hw_params,
+};
+
+static int arndale_wm1811_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ unsigned int rfs, rclk;
+
+ /* Ensure AIF1CLK is >= 3 MHz for optimal performance */
+ if (params_width(params) == 24)
+ rfs = 384;
+ else if (params_rate(params) == 8000 || params_rate(params) == 11025)
+ rfs = 512;
+ else
+ rfs = 256;
+
+ rclk = params_rate(params) * rfs;
+
+ /*
+ * We add 1 to the frequency value to ensure proper EPLL setting
+ * for each audio sampling rate (see epll_24mhz_tbl in drivers/clk/
+ * samsung/clk-exynos5250.c for list of available EPLL rates).
+ * The CODEC uses clk API and the value will be rounded hence the MCLK1
+ * clock's frequency will still be exact multiple of the sample rate.
+ */
+ return snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1,
+ rclk + 1, SND_SOC_CLOCK_IN);
+}
+
+static struct snd_soc_ops arndale_wm1811_ops = {
+ .hw_params = arndale_wm1811_hw_params,
};
SND_SOC_DAILINK_DEFS(rt5631_hifi,
DAILINK_COMP_ARRAY(COMP_EMPTY()),
- DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-hifi")),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-aif1")),
DAILINK_COMP_ARRAY(COMP_EMPTY()));
static struct snd_soc_dai_link arndale_rt5631_dai[] = {
@@ -63,11 +96,28 @@ static struct snd_soc_dai_link arndale_rt5631_dai[] = {
.dai_fmt = SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
| SND_SOC_DAIFMT_CBS_CFS,
- .ops = &arndale_ops,
+ .ops = &arndale_rt5631_ops,
SND_SOC_DAILINK_REG(rt5631_hifi),
},
};
+SND_SOC_DAILINK_DEFS(wm1811_hifi,
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
+static struct snd_soc_dai_link arndale_wm1811_dai[] = {
+ {
+ .name = "WM1811 HiFi",
+ .stream_name = "Primary",
+ .dai_fmt = SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .ops = &arndale_wm1811_ops,
+ SND_SOC_DAILINK_REG(wm1811_hifi),
+ },
+};
+
static struct snd_soc_card arndale_rt5631 = {
.name = "Arndale RT5631",
.owner = THIS_MODULE,
@@ -75,6 +125,13 @@ static struct snd_soc_card arndale_rt5631 = {
.num_links = ARRAY_SIZE(arndale_rt5631_dai),
};
+static struct snd_soc_card arndale_wm1811 = {
+ .name = "Arndale WM1811",
+ .owner = THIS_MODULE,
+ .dai_link = arndale_wm1811_dai,
+ .num_links = ARRAY_SIZE(arndale_wm1811_dai),
+};
+
static void arndale_put_of_nodes(struct snd_soc_card *card)
{
struct snd_soc_dai_link *dai_link;
@@ -89,10 +146,11 @@ static void arndale_put_of_nodes(struct snd_soc_card *card)
static int arndale_audio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- struct snd_soc_card *card = &arndale_rt5631;
+ struct snd_soc_card *card;
struct snd_soc_dai_link *dai_link;
int ret;
+ card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);
card->dev = &pdev->dev;
dai_link = card->dai_link;
@@ -134,18 +192,19 @@ static int arndale_audio_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
- { .compatible = "samsung,arndale-rt5631", },
- { .compatible = "samsung,arndale-alc5631", },
+static const struct of_device_id arndale_audio_of_match[] = {
+ { .compatible = "samsung,arndale-rt5631", .data = &arndale_rt5631 },
+ { .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 },
+ { .compatible = "samsung,arndale-wm1811", .data = &arndale_wm1811 },
{},
};
-MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
+MODULE_DEVICE_TABLE(of, arndale_audio_of_match);
static struct platform_driver arndale_audio_driver = {
.driver = {
- .name = "arndale-audio",
+ .name = "arndale-audio",
.pm = &snd_soc_pm_ops,
- .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
+ .of_match_table = arndale_audio_of_match,
},
.probe = arndale_audio_probe,
.remove = arndale_audio_remove,