diff options
-rw-r--r-- | sound/soc/samsung/Kconfig | 2 | ||||
-rw-r--r-- | sound/soc/samsung/arndale_rt5631.c | 85 |
2 files changed, 74 insertions, 13 deletions
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 638983123d8f..6803cbfa9e46 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -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" diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c index 004c84fafad9..d64602950cbd 100644 --- a/sound/soc/samsung/arndale_rt5631.c +++ b/sound/soc/samsung/arndale_rt5631.c @@ -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, |