141ce2ac0SSylwester Nawrocki // SPDX-License-Identifier: GPL-2.0+ 241ce2ac0SSylwester Nawrocki // 341ce2ac0SSylwester Nawrocki // Bells audio support 441ce2ac0SSylwester Nawrocki // 541ce2ac0SSylwester Nawrocki // Copyright 2012 Wolfson Microelectronics 6b545dd92SMark Brown 7b545dd92SMark Brown #include <sound/soc.h> 8b545dd92SMark Brown #include <sound/soc-dapm.h> 9b545dd92SMark Brown #include <sound/jack.h> 10b545dd92SMark Brown #include <linux/gpio.h> 11b545dd92SMark Brown #include <linux/module.h> 12b545dd92SMark Brown 13b545dd92SMark Brown #include "../codecs/wm5102.h" 14b545dd92SMark Brown #include "../codecs/wm9081.h" 15b545dd92SMark Brown 16b545dd92SMark Brown /* BCLK2 is fixed at this currently */ 17b545dd92SMark Brown #define BCLK2_RATE (64 * 8000) 18b545dd92SMark Brown 19b545dd92SMark Brown /* 20b545dd92SMark Brown * Expect a 24.576MHz crystal if one is fitted (the driver will function 21b545dd92SMark Brown * if this is not fitted). 22b545dd92SMark Brown */ 23b545dd92SMark Brown #define MCLK_RATE 24576000 24b545dd92SMark Brown 25344c5edeSMark Brown #define SYS_AUDIO_RATE 44100 26208229ecSDimitris Papastamos #define SYS_MCLK_RATE (SYS_AUDIO_RATE * 512) 27344c5edeSMark Brown 28344c5edeSMark Brown #define DAI_AP_DSP 0 29344c5edeSMark Brown #define DAI_DSP_CODEC 1 30344c5edeSMark Brown #define DAI_CODEC_CP 2 31344c5edeSMark Brown #define DAI_CODEC_SUB 3 32b545dd92SMark Brown 33b1387078SMark Brown struct bells_drvdata { 34b1387078SMark Brown int sysclk_rate; 35b1387078SMark Brown int asyncclk_rate; 36b1387078SMark Brown }; 37b1387078SMark Brown 388d47e8a5SMark Brown static struct bells_drvdata wm2200_drvdata = { 398d47e8a5SMark Brown .sysclk_rate = 22579200, 408d47e8a5SMark Brown }; 418d47e8a5SMark Brown 42b1387078SMark Brown static struct bells_drvdata wm5102_drvdata = { 43b1387078SMark Brown .sysclk_rate = 45158400, 44b1387078SMark Brown .asyncclk_rate = 49152000, 45b1387078SMark Brown }; 46b1387078SMark Brown 47b1387078SMark Brown static struct bells_drvdata wm5110_drvdata = { 48b1387078SMark Brown .sysclk_rate = 135475200, 49b1387078SMark Brown .asyncclk_rate = 147456000, 50b1387078SMark Brown }; 51b1387078SMark Brown 52b545dd92SMark Brown static int bells_set_bias_level(struct snd_soc_card *card, 53b545dd92SMark Brown struct snd_soc_dapm_context *dapm, 54b545dd92SMark Brown enum snd_soc_bias_level level) 55b545dd92SMark Brown { 565015920aSMengdong Lin struct snd_soc_pcm_runtime *rtd; 575015920aSMengdong Lin struct snd_soc_dai *codec_dai; 58f4a2be1cSKuninori Morimoto struct snd_soc_component *component; 59b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 60b545dd92SMark Brown int ret; 61b545dd92SMark Brown 624468189fSKuninori Morimoto rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]); 637de6b6bcSKuninori Morimoto codec_dai = asoc_rtd_to_codec(rtd, 0); 64f4a2be1cSKuninori Morimoto component = codec_dai->component; 655015920aSMengdong Lin 66b545dd92SMark Brown if (dapm->dev != codec_dai->dev) 67b545dd92SMark Brown return 0; 68b545dd92SMark Brown 69b545dd92SMark Brown switch (level) { 70b545dd92SMark Brown case SND_SOC_BIAS_PREPARE: 71b1387078SMark Brown if (dapm->bias_level != SND_SOC_BIAS_STANDBY) 72b1387078SMark Brown break; 73b1387078SMark Brown 74f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_pll(component, WM5102_FLL1, 75b545dd92SMark Brown ARIZONA_FLL_SRC_MCLK1, 76b545dd92SMark Brown MCLK_RATE, 77b1387078SMark Brown bells->sysclk_rate); 78b545dd92SMark Brown if (ret < 0) 79b545dd92SMark Brown pr_err("Failed to start FLL: %d\n", ret); 80b545dd92SMark Brown 81b1387078SMark Brown if (bells->asyncclk_rate) { 82f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_pll(component, WM5102_FLL2, 83b545dd92SMark Brown ARIZONA_FLL_SRC_AIF2BCLK, 84b545dd92SMark Brown BCLK2_RATE, 85b1387078SMark Brown bells->asyncclk_rate); 86b545dd92SMark Brown if (ret < 0) 87b545dd92SMark Brown pr_err("Failed to start FLL: %d\n", ret); 88b545dd92SMark Brown } 89b545dd92SMark Brown break; 90b545dd92SMark Brown 91b545dd92SMark Brown default: 92b545dd92SMark Brown break; 93b545dd92SMark Brown } 94b545dd92SMark Brown 95b545dd92SMark Brown return 0; 96b545dd92SMark Brown } 97b545dd92SMark Brown 98b545dd92SMark Brown static int bells_set_bias_level_post(struct snd_soc_card *card, 99b545dd92SMark Brown struct snd_soc_dapm_context *dapm, 100b545dd92SMark Brown enum snd_soc_bias_level level) 101b545dd92SMark Brown { 1025015920aSMengdong Lin struct snd_soc_pcm_runtime *rtd; 1035015920aSMengdong Lin struct snd_soc_dai *codec_dai; 104f4a2be1cSKuninori Morimoto struct snd_soc_component *component; 105b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 106b545dd92SMark Brown int ret; 107b545dd92SMark Brown 1084468189fSKuninori Morimoto rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]); 1097de6b6bcSKuninori Morimoto codec_dai = asoc_rtd_to_codec(rtd, 0); 110f4a2be1cSKuninori Morimoto component = codec_dai->component; 1115015920aSMengdong Lin 112b545dd92SMark Brown if (dapm->dev != codec_dai->dev) 113b545dd92SMark Brown return 0; 114b545dd92SMark Brown 115b545dd92SMark Brown switch (level) { 116b545dd92SMark Brown case SND_SOC_BIAS_STANDBY: 117f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_pll(component, WM5102_FLL1, 0, 0, 0); 118b545dd92SMark Brown if (ret < 0) { 119b545dd92SMark Brown pr_err("Failed to stop FLL: %d\n", ret); 120b545dd92SMark Brown return ret; 121b545dd92SMark Brown } 122b545dd92SMark Brown 123b1387078SMark Brown if (bells->asyncclk_rate) { 124f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_pll(component, WM5102_FLL2, 125b1387078SMark Brown 0, 0, 0); 126b545dd92SMark Brown if (ret < 0) { 127b545dd92SMark Brown pr_err("Failed to stop FLL: %d\n", ret); 128b545dd92SMark Brown return ret; 129b545dd92SMark Brown } 130b1387078SMark Brown } 131b545dd92SMark Brown break; 132b545dd92SMark Brown 133b545dd92SMark Brown default: 134b545dd92SMark Brown break; 135b545dd92SMark Brown } 136b545dd92SMark Brown 137b545dd92SMark Brown dapm->bias_level = level; 138b545dd92SMark Brown 139b545dd92SMark Brown return 0; 140b545dd92SMark Brown } 141b545dd92SMark Brown 142b545dd92SMark Brown static int bells_late_probe(struct snd_soc_card *card) 143b545dd92SMark Brown { 144b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 1455015920aSMengdong Lin struct snd_soc_pcm_runtime *rtd; 146f4a2be1cSKuninori Morimoto struct snd_soc_component *wm0010; 147f4a2be1cSKuninori Morimoto struct snd_soc_component *component; 1485015920aSMengdong Lin struct snd_soc_dai *aif1_dai; 149b1387078SMark Brown struct snd_soc_dai *aif2_dai; 150b1387078SMark Brown struct snd_soc_dai *aif3_dai; 151b1387078SMark Brown struct snd_soc_dai *wm9081_dai; 152b545dd92SMark Brown int ret; 153b545dd92SMark Brown 1544468189fSKuninori Morimoto rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_AP_DSP]); 1557de6b6bcSKuninori Morimoto wm0010 = asoc_rtd_to_codec(rtd, 0)->component; 1565015920aSMengdong Lin 1574468189fSKuninori Morimoto rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_DSP_CODEC]); 1587de6b6bcSKuninori Morimoto component = asoc_rtd_to_codec(rtd, 0)->component; 1597de6b6bcSKuninori Morimoto aif1_dai = asoc_rtd_to_codec(rtd, 0); 1605015920aSMengdong Lin 161f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK, 162b1387078SMark Brown ARIZONA_CLK_SRC_FLL1, 163b1387078SMark Brown bells->sysclk_rate, 164b1387078SMark Brown SND_SOC_CLOCK_IN); 165b1387078SMark Brown if (ret != 0) { 166f4a2be1cSKuninori Morimoto dev_err(component->dev, "Failed to set SYSCLK: %d\n", ret); 167b1387078SMark Brown return ret; 168b1387078SMark Brown } 169b1387078SMark Brown 170f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0); 171344c5edeSMark Brown if (ret != 0) { 172344c5edeSMark Brown dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret); 173344c5edeSMark Brown return ret; 174344c5edeSMark Brown } 175344c5edeSMark Brown 176b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); 177b1387078SMark Brown if (ret != 0) 178b545dd92SMark Brown dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); 179b1387078SMark Brown 180f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_OPCLK, 0, 181b1387078SMark Brown SYS_MCLK_RATE, SND_SOC_CLOCK_OUT); 182b1387078SMark Brown if (ret != 0) 183f4a2be1cSKuninori Morimoto dev_err(component->dev, "Failed to set OPCLK: %d\n", ret); 184b1387078SMark Brown 185b1387078SMark Brown if (card->num_rtd == DAI_CODEC_CP) 186b1387078SMark Brown return 0; 187b1387078SMark Brown 188f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK, 189b1387078SMark Brown ARIZONA_CLK_SRC_FLL2, 190b1387078SMark Brown bells->asyncclk_rate, 191b1387078SMark Brown SND_SOC_CLOCK_IN); 192b1387078SMark Brown if (ret != 0) { 193f4a2be1cSKuninori Morimoto dev_err(component->dev, "Failed to set ASYNCCLK: %d\n", ret); 194b545dd92SMark Brown return ret; 195b545dd92SMark Brown } 196b545dd92SMark Brown 1974468189fSKuninori Morimoto rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_CODEC_CP]); 1987de6b6bcSKuninori Morimoto aif2_dai = asoc_rtd_to_cpu(rtd, 0); 199b1387078SMark Brown 200b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); 201b545dd92SMark Brown if (ret != 0) { 202b545dd92SMark Brown dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); 203b545dd92SMark Brown return ret; 204b545dd92SMark Brown } 205b545dd92SMark Brown 206b1387078SMark Brown if (card->num_rtd == DAI_CODEC_SUB) 207b1387078SMark Brown return 0; 208b1387078SMark Brown 2094468189fSKuninori Morimoto rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[DAI_CODEC_SUB]); 2107de6b6bcSKuninori Morimoto aif3_dai = asoc_rtd_to_cpu(rtd, 0); 2117de6b6bcSKuninori Morimoto wm9081_dai = asoc_rtd_to_codec(rtd, 0); 212b1387078SMark Brown 213b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); 214b545dd92SMark Brown if (ret != 0) { 215b545dd92SMark Brown dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); 216b545dd92SMark Brown return ret; 217b545dd92SMark Brown } 218b545dd92SMark Brown 219f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(wm9081_dai->component, WM9081_SYSCLK_MCLK, 220344c5edeSMark Brown 0, SYS_MCLK_RATE, 0); 221b545dd92SMark Brown if (ret != 0) { 222b545dd92SMark Brown dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); 223b545dd92SMark Brown return ret; 224b545dd92SMark Brown } 225b545dd92SMark Brown 226b545dd92SMark Brown return 0; 227b545dd92SMark Brown } 228b545dd92SMark Brown 229b545dd92SMark Brown static const struct snd_soc_pcm_stream baseband_params = { 230b545dd92SMark Brown .formats = SNDRV_PCM_FMTBIT_S32_LE, 231b545dd92SMark Brown .rate_min = 8000, 232b545dd92SMark Brown .rate_max = 8000, 233b545dd92SMark Brown .channels_min = 2, 234b545dd92SMark Brown .channels_max = 2, 235b545dd92SMark Brown }; 236b545dd92SMark Brown 237b545dd92SMark Brown static const struct snd_soc_pcm_stream sub_params = { 238b545dd92SMark Brown .formats = SNDRV_PCM_FMTBIT_S32_LE, 239344c5edeSMark Brown .rate_min = SYS_AUDIO_RATE, 240344c5edeSMark Brown .rate_max = SYS_AUDIO_RATE, 241b545dd92SMark Brown .channels_min = 2, 242b545dd92SMark Brown .channels_max = 2, 243b545dd92SMark Brown }; 244b545dd92SMark Brown 2455af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm2200_cpu_dsp, 2465af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), 2475af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "wm0010-sdi1")), 2485af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); 2495af5e760SKuninori Morimoto 2505af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm2200_dsp_codec, 2515af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("wm0010-sdi2")), 2525af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("wm2200.1-003a", "wm2200"))); 2535af5e760SKuninori Morimoto 2548d47e8a5SMark Brown static struct snd_soc_dai_link bells_dai_wm2200[] = { 2558d47e8a5SMark Brown { 2568d47e8a5SMark Brown .name = "CPU-DSP", 2578d47e8a5SMark Brown .stream_name = "CPU-DSP", 2588d47e8a5SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 2598d47e8a5SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 2605af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm2200_cpu_dsp), 2618d47e8a5SMark Brown }, 2628d47e8a5SMark Brown { 2638d47e8a5SMark Brown .name = "DSP-CODEC", 2648d47e8a5SMark Brown .stream_name = "DSP-CODEC", 2658d47e8a5SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 2668d47e8a5SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 267*e7a73b05SKuninori Morimoto .c2c_params = &sub_params, 268*e7a73b05SKuninori Morimoto .num_c2c_params = 1, 2698d47e8a5SMark Brown .ignore_suspend = 1, 2705af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm2200_dsp_codec), 2718d47e8a5SMark Brown }, 2728d47e8a5SMark Brown }; 2738d47e8a5SMark Brown 2745af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm5102_cpu_dsp, 2755af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), 2765af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "wm0010-sdi1")), 2775af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); 2785af5e760SKuninori Morimoto 2795af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm5102_dsp_codec, 2805af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("wm0010-sdi2")), 2815af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("wm5102-codec", "wm5102-aif1"))); 2825af5e760SKuninori Morimoto 2835af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm5102_baseband, 2845af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("wm5102-aif2")), 2855af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("wm1250-ev1.1-0027", "wm1250-ev1"))); 2865af5e760SKuninori Morimoto 2875af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm5102_sub, 2885af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("wm5102-aif3")), 2895af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("wm9081.1-006c", "wm9081-hifi"))); 2905af5e760SKuninori Morimoto 291b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5102[] = { 292b545dd92SMark Brown { 293344c5edeSMark Brown .name = "CPU-DSP", 294344c5edeSMark Brown .stream_name = "CPU-DSP", 295344c5edeSMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 296344c5edeSMark Brown | SND_SOC_DAIFMT_CBM_CFM, 2975af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm5102_cpu_dsp), 298344c5edeSMark Brown }, 299344c5edeSMark Brown { 300344c5edeSMark Brown .name = "DSP-CODEC", 301344c5edeSMark Brown .stream_name = "DSP-CODEC", 302b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 303b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 304*e7a73b05SKuninori Morimoto .c2c_params = &sub_params, 305*e7a73b05SKuninori Morimoto .num_c2c_params = 1, 306344c5edeSMark Brown .ignore_suspend = 1, 3075af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm5102_dsp_codec), 308b545dd92SMark Brown }, 309b545dd92SMark Brown { 310b545dd92SMark Brown .name = "Baseband", 311b545dd92SMark Brown .stream_name = "Baseband", 312b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 313b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 314b545dd92SMark Brown .ignore_suspend = 1, 315*e7a73b05SKuninori Morimoto .c2c_params = &baseband_params, 316*e7a73b05SKuninori Morimoto .num_c2c_params = 1, 3175af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm5102_baseband), 318b545dd92SMark Brown }, 319b545dd92SMark Brown { 320b545dd92SMark Brown .name = "Sub", 321b545dd92SMark Brown .stream_name = "Sub", 322b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 323b545dd92SMark Brown | SND_SOC_DAIFMT_CBS_CFS, 324b545dd92SMark Brown .ignore_suspend = 1, 325*e7a73b05SKuninori Morimoto .c2c_params = &sub_params, 326*e7a73b05SKuninori Morimoto .num_c2c_params = 1, 3275af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm5102_sub), 328b545dd92SMark Brown }, 329b545dd92SMark Brown }; 330b545dd92SMark Brown 3315af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm5110_cpu_dsp, 3325af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), 3335af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("spi0.0", "wm0010-sdi1")), 3345af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); 3355af5e760SKuninori Morimoto 3365af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm5110_dsp_codec, 3375af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("wm0010-sdi2")), 3385af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("wm5110-codec", "wm5110-aif1"))); 3395af5e760SKuninori Morimoto 3405af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm5110_baseband, 3415af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("wm5110-aif2")), 3425af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("wm1250-ev1.1-0027", "wm1250-ev1"))); 3435af5e760SKuninori Morimoto 3445af5e760SKuninori Morimoto 3455af5e760SKuninori Morimoto SND_SOC_DAILINK_DEFS(wm5110_sub, 3465af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CPU("wm5110-aif3")), 3475af5e760SKuninori Morimoto DAILINK_COMP_ARRAY(COMP_CODEC("wm9081.1-006c", "wm9081-hifi"))); 3485af5e760SKuninori Morimoto 349b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5110[] = { 350b545dd92SMark Brown { 351344c5edeSMark Brown .name = "CPU-DSP", 352344c5edeSMark Brown .stream_name = "CPU-DSP", 353344c5edeSMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 354344c5edeSMark Brown | SND_SOC_DAIFMT_CBM_CFM, 3555af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm5110_cpu_dsp), 356344c5edeSMark Brown }, 357344c5edeSMark Brown { 358344c5edeSMark Brown .name = "DSP-CODEC", 359344c5edeSMark Brown .stream_name = "DSP-CODEC", 360b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 361b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 362*e7a73b05SKuninori Morimoto .c2c_params = &sub_params, 363*e7a73b05SKuninori Morimoto .num_c2c_params = 1, 364344c5edeSMark Brown .ignore_suspend = 1, 3655af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm5110_dsp_codec), 366b545dd92SMark Brown }, 367b545dd92SMark Brown { 368b545dd92SMark Brown .name = "Baseband", 369b545dd92SMark Brown .stream_name = "Baseband", 370b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 371b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 372b545dd92SMark Brown .ignore_suspend = 1, 373*e7a73b05SKuninori Morimoto .c2c_params = &baseband_params, 374*e7a73b05SKuninori Morimoto .num_c2c_params = 1, 3755af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm5110_baseband), 376b545dd92SMark Brown }, 377b545dd92SMark Brown { 378b545dd92SMark Brown .name = "Sub", 379b545dd92SMark Brown .stream_name = "Sub", 380b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 381b545dd92SMark Brown | SND_SOC_DAIFMT_CBS_CFS, 382b545dd92SMark Brown .ignore_suspend = 1, 383*e7a73b05SKuninori Morimoto .c2c_params = &sub_params, 384*e7a73b05SKuninori Morimoto .num_c2c_params = 1, 3855af5e760SKuninori Morimoto SND_SOC_DAILINK_REG(wm5110_sub), 386b545dd92SMark Brown }, 387b545dd92SMark Brown }; 388b545dd92SMark Brown 389b545dd92SMark Brown static struct snd_soc_codec_conf bells_codec_conf[] = { 390b545dd92SMark Brown { 3913874b215SKuninori Morimoto .dlc = COMP_CODEC_CONF("wm9081.1-006c"), 392b545dd92SMark Brown .name_prefix = "Sub", 393b545dd92SMark Brown }, 394b545dd92SMark Brown }; 395b545dd92SMark Brown 3965449fd7bSRikard Falkeborn static const struct snd_soc_dapm_widget bells_widgets[] = { 397939d3c6aSCharles Keepax SND_SOC_DAPM_MIC("DMIC", NULL), 398939d3c6aSCharles Keepax }; 399939d3c6aSCharles Keepax 4005449fd7bSRikard Falkeborn static const struct snd_soc_dapm_route bells_routes[] = { 401b545dd92SMark Brown { "Sub CLK_SYS", NULL, "OPCLK" }, 402b3a6006eSCharles Keepax { "CLKIN", NULL, "OPCLK" }, 403939d3c6aSCharles Keepax 404939d3c6aSCharles Keepax { "DMIC", NULL, "MICBIAS2" }, 405939d3c6aSCharles Keepax { "IN2L", NULL, "DMIC" }, 406939d3c6aSCharles Keepax { "IN2R", NULL, "DMIC" }, 407b545dd92SMark Brown }; 408b545dd92SMark Brown 409b545dd92SMark Brown static struct snd_soc_card bells_cards[] = { 410b545dd92SMark Brown { 4118d47e8a5SMark Brown .name = "Bells WM2200", 4128d47e8a5SMark Brown .owner = THIS_MODULE, 4138d47e8a5SMark Brown .dai_link = bells_dai_wm2200, 4148d47e8a5SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm2200), 4158d47e8a5SMark Brown .codec_conf = bells_codec_conf, 4168d47e8a5SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 4178d47e8a5SMark Brown 4188d47e8a5SMark Brown .late_probe = bells_late_probe, 4198d47e8a5SMark Brown 420939d3c6aSCharles Keepax .dapm_widgets = bells_widgets, 421939d3c6aSCharles Keepax .num_dapm_widgets = ARRAY_SIZE(bells_widgets), 4228d47e8a5SMark Brown .dapm_routes = bells_routes, 4238d47e8a5SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 4248d47e8a5SMark Brown 4258d47e8a5SMark Brown .set_bias_level = bells_set_bias_level, 4268d47e8a5SMark Brown .set_bias_level_post = bells_set_bias_level_post, 4278d47e8a5SMark Brown 4288d47e8a5SMark Brown .drvdata = &wm2200_drvdata, 4298d47e8a5SMark Brown }, 4308d47e8a5SMark Brown { 431b545dd92SMark Brown .name = "Bells WM5102", 432b545dd92SMark Brown .owner = THIS_MODULE, 433b545dd92SMark Brown .dai_link = bells_dai_wm5102, 434b545dd92SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm5102), 435b545dd92SMark Brown .codec_conf = bells_codec_conf, 436b545dd92SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 437b545dd92SMark Brown 438b545dd92SMark Brown .late_probe = bells_late_probe, 439b545dd92SMark Brown 440939d3c6aSCharles Keepax .dapm_widgets = bells_widgets, 441939d3c6aSCharles Keepax .num_dapm_widgets = ARRAY_SIZE(bells_widgets), 442b545dd92SMark Brown .dapm_routes = bells_routes, 443b545dd92SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 444b545dd92SMark Brown 445b545dd92SMark Brown .set_bias_level = bells_set_bias_level, 446b545dd92SMark Brown .set_bias_level_post = bells_set_bias_level_post, 447b1387078SMark Brown 448b1387078SMark Brown .drvdata = &wm5102_drvdata, 449b545dd92SMark Brown }, 450b545dd92SMark Brown { 451b545dd92SMark Brown .name = "Bells WM5110", 452b545dd92SMark Brown .owner = THIS_MODULE, 453b545dd92SMark Brown .dai_link = bells_dai_wm5110, 454b545dd92SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm5110), 455b545dd92SMark Brown .codec_conf = bells_codec_conf, 456b545dd92SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 457b545dd92SMark Brown 458b545dd92SMark Brown .late_probe = bells_late_probe, 459b545dd92SMark Brown 460939d3c6aSCharles Keepax .dapm_widgets = bells_widgets, 461939d3c6aSCharles Keepax .num_dapm_widgets = ARRAY_SIZE(bells_widgets), 462b545dd92SMark Brown .dapm_routes = bells_routes, 463b545dd92SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 464b545dd92SMark Brown 465b545dd92SMark Brown .set_bias_level = bells_set_bias_level, 466b545dd92SMark Brown .set_bias_level_post = bells_set_bias_level_post, 467b1387078SMark Brown 468b1387078SMark Brown .drvdata = &wm5110_drvdata, 469b545dd92SMark Brown }, 470b545dd92SMark Brown }; 471b545dd92SMark Brown 472fdca21adSBill Pemberton static int bells_probe(struct platform_device *pdev) 473b545dd92SMark Brown { 474b545dd92SMark Brown int ret; 475b545dd92SMark Brown 476b545dd92SMark Brown bells_cards[pdev->id].dev = &pdev->dev; 477b545dd92SMark Brown 478c583883eSTushar Behera ret = devm_snd_soc_register_card(&pdev->dev, &bells_cards[pdev->id]); 479c583883eSTushar Behera if (ret) 480b545dd92SMark Brown dev_err(&pdev->dev, 481b545dd92SMark Brown "snd_soc_register_card(%s) failed: %d\n", 482b545dd92SMark Brown bells_cards[pdev->id].name, ret); 483c583883eSTushar Behera 484b545dd92SMark Brown return ret; 485b545dd92SMark Brown } 486b545dd92SMark Brown 487b545dd92SMark Brown static struct platform_driver bells_driver = { 488b545dd92SMark Brown .driver = { 489b545dd92SMark Brown .name = "bells", 490b545dd92SMark Brown .pm = &snd_soc_pm_ops, 491b545dd92SMark Brown }, 492b545dd92SMark Brown .probe = bells_probe, 493b545dd92SMark Brown }; 494b545dd92SMark Brown 495b545dd92SMark Brown module_platform_driver(bells_driver); 496b545dd92SMark Brown 497b545dd92SMark Brown MODULE_DESCRIPTION("Bells audio support"); 498b545dd92SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 499b545dd92SMark Brown MODULE_LICENSE("GPL"); 500b545dd92SMark Brown MODULE_ALIAS("platform:bells"); 501