1b545dd92SMark Brown /* 2b545dd92SMark Brown * Bells audio support 3b545dd92SMark Brown * 4b545dd92SMark Brown * Copyright 2012 Wolfson Microelectronics 5b545dd92SMark Brown * 6b545dd92SMark Brown * This program is free software; you can redistribute it and/or modify it 7b545dd92SMark Brown * under the terms of the GNU General Public License as published by the 8b545dd92SMark Brown * Free Software Foundation; either version 2 of the License, or (at your 9b545dd92SMark Brown * option) any later version. 10b545dd92SMark Brown */ 11b545dd92SMark Brown 12b545dd92SMark Brown #include <sound/soc.h> 13b545dd92SMark Brown #include <sound/soc-dapm.h> 14b545dd92SMark Brown #include <sound/jack.h> 15b545dd92SMark Brown #include <linux/gpio.h> 16b545dd92SMark Brown #include <linux/module.h> 17b545dd92SMark Brown 18b545dd92SMark Brown #include "../codecs/wm5102.h" 19b545dd92SMark Brown #include "../codecs/wm9081.h" 20b545dd92SMark Brown 21b545dd92SMark Brown /* BCLK2 is fixed at this currently */ 22b545dd92SMark Brown #define BCLK2_RATE (64 * 8000) 23b545dd92SMark Brown 24b545dd92SMark Brown /* 25b545dd92SMark Brown * Expect a 24.576MHz crystal if one is fitted (the driver will function 26b545dd92SMark Brown * if this is not fitted). 27b545dd92SMark Brown */ 28b545dd92SMark Brown #define MCLK_RATE 24576000 29b545dd92SMark Brown 30344c5edeSMark Brown #define SYS_AUDIO_RATE 44100 31208229ecSDimitris Papastamos #define SYS_MCLK_RATE (SYS_AUDIO_RATE * 512) 32344c5edeSMark Brown 33344c5edeSMark Brown #define DAI_AP_DSP 0 34344c5edeSMark Brown #define DAI_DSP_CODEC 1 35344c5edeSMark Brown #define DAI_CODEC_CP 2 36344c5edeSMark Brown #define DAI_CODEC_SUB 3 37b545dd92SMark Brown 38b1387078SMark Brown struct bells_drvdata { 39b1387078SMark Brown int sysclk_rate; 40b1387078SMark Brown int asyncclk_rate; 41b1387078SMark Brown }; 42b1387078SMark Brown 438d47e8a5SMark Brown static struct bells_drvdata wm2200_drvdata = { 448d47e8a5SMark Brown .sysclk_rate = 22579200, 458d47e8a5SMark Brown }; 468d47e8a5SMark Brown 47b1387078SMark Brown static struct bells_drvdata wm5102_drvdata = { 48b1387078SMark Brown .sysclk_rate = 45158400, 49b1387078SMark Brown .asyncclk_rate = 49152000, 50b1387078SMark Brown }; 51b1387078SMark Brown 52b1387078SMark Brown static struct bells_drvdata wm5110_drvdata = { 53b1387078SMark Brown .sysclk_rate = 135475200, 54b1387078SMark Brown .asyncclk_rate = 147456000, 55b1387078SMark Brown }; 56b1387078SMark Brown 57b545dd92SMark Brown static int bells_set_bias_level(struct snd_soc_card *card, 58b545dd92SMark Brown struct snd_soc_dapm_context *dapm, 59b545dd92SMark Brown enum snd_soc_bias_level level) 60b545dd92SMark Brown { 615015920aSMengdong Lin struct snd_soc_pcm_runtime *rtd; 625015920aSMengdong Lin struct snd_soc_dai *codec_dai; 63*f4a2be1cSKuninori Morimoto struct snd_soc_component *component; 64b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 65b545dd92SMark Brown int ret; 66b545dd92SMark Brown 675015920aSMengdong Lin rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); 685015920aSMengdong Lin codec_dai = rtd->codec_dai; 69*f4a2be1cSKuninori Morimoto component = codec_dai->component; 705015920aSMengdong Lin 71b545dd92SMark Brown if (dapm->dev != codec_dai->dev) 72b545dd92SMark Brown return 0; 73b545dd92SMark Brown 74b545dd92SMark Brown switch (level) { 75b545dd92SMark Brown case SND_SOC_BIAS_PREPARE: 76b1387078SMark Brown if (dapm->bias_level != SND_SOC_BIAS_STANDBY) 77b1387078SMark Brown break; 78b1387078SMark Brown 79*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_pll(component, WM5102_FLL1, 80b545dd92SMark Brown ARIZONA_FLL_SRC_MCLK1, 81b545dd92SMark Brown MCLK_RATE, 82b1387078SMark Brown bells->sysclk_rate); 83b545dd92SMark Brown if (ret < 0) 84b545dd92SMark Brown pr_err("Failed to start FLL: %d\n", ret); 85b545dd92SMark Brown 86b1387078SMark Brown if (bells->asyncclk_rate) { 87*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_pll(component, WM5102_FLL2, 88b545dd92SMark Brown ARIZONA_FLL_SRC_AIF2BCLK, 89b545dd92SMark Brown BCLK2_RATE, 90b1387078SMark Brown bells->asyncclk_rate); 91b545dd92SMark Brown if (ret < 0) 92b545dd92SMark Brown pr_err("Failed to start FLL: %d\n", ret); 93b545dd92SMark Brown } 94b545dd92SMark Brown break; 95b545dd92SMark Brown 96b545dd92SMark Brown default: 97b545dd92SMark Brown break; 98b545dd92SMark Brown } 99b545dd92SMark Brown 100b545dd92SMark Brown return 0; 101b545dd92SMark Brown } 102b545dd92SMark Brown 103b545dd92SMark Brown static int bells_set_bias_level_post(struct snd_soc_card *card, 104b545dd92SMark Brown struct snd_soc_dapm_context *dapm, 105b545dd92SMark Brown enum snd_soc_bias_level level) 106b545dd92SMark Brown { 1075015920aSMengdong Lin struct snd_soc_pcm_runtime *rtd; 1085015920aSMengdong Lin struct snd_soc_dai *codec_dai; 109*f4a2be1cSKuninori Morimoto struct snd_soc_component *component; 110b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 111b545dd92SMark Brown int ret; 112b545dd92SMark Brown 1135015920aSMengdong Lin rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); 1145015920aSMengdong Lin codec_dai = rtd->codec_dai; 115*f4a2be1cSKuninori Morimoto component = codec_dai->component; 1165015920aSMengdong Lin 117b545dd92SMark Brown if (dapm->dev != codec_dai->dev) 118b545dd92SMark Brown return 0; 119b545dd92SMark Brown 120b545dd92SMark Brown switch (level) { 121b545dd92SMark Brown case SND_SOC_BIAS_STANDBY: 122*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_pll(component, WM5102_FLL1, 0, 0, 0); 123b545dd92SMark Brown if (ret < 0) { 124b545dd92SMark Brown pr_err("Failed to stop FLL: %d\n", ret); 125b545dd92SMark Brown return ret; 126b545dd92SMark Brown } 127b545dd92SMark Brown 128b1387078SMark Brown if (bells->asyncclk_rate) { 129*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_pll(component, WM5102_FLL2, 130b1387078SMark Brown 0, 0, 0); 131b545dd92SMark Brown if (ret < 0) { 132b545dd92SMark Brown pr_err("Failed to stop FLL: %d\n", ret); 133b545dd92SMark Brown return ret; 134b545dd92SMark Brown } 135b1387078SMark Brown } 136b545dd92SMark Brown break; 137b545dd92SMark Brown 138b545dd92SMark Brown default: 139b545dd92SMark Brown break; 140b545dd92SMark Brown } 141b545dd92SMark Brown 142b545dd92SMark Brown dapm->bias_level = level; 143b545dd92SMark Brown 144b545dd92SMark Brown return 0; 145b545dd92SMark Brown } 146b545dd92SMark Brown 147b545dd92SMark Brown static int bells_late_probe(struct snd_soc_card *card) 148b545dd92SMark Brown { 149b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 1505015920aSMengdong Lin struct snd_soc_pcm_runtime *rtd; 151*f4a2be1cSKuninori Morimoto struct snd_soc_component *wm0010; 152*f4a2be1cSKuninori Morimoto struct snd_soc_component *component; 1535015920aSMengdong Lin struct snd_soc_dai *aif1_dai; 154b1387078SMark Brown struct snd_soc_dai *aif2_dai; 155b1387078SMark Brown struct snd_soc_dai *aif3_dai; 156b1387078SMark Brown struct snd_soc_dai *wm9081_dai; 157b545dd92SMark Brown int ret; 158b545dd92SMark Brown 1595015920aSMengdong Lin rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name); 160*f4a2be1cSKuninori Morimoto wm0010 = rtd->codec_dai->component; 1615015920aSMengdong Lin 1625015920aSMengdong Lin rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); 163*f4a2be1cSKuninori Morimoto component = rtd->codec_dai->component; 1645015920aSMengdong Lin aif1_dai = rtd->codec_dai; 1655015920aSMengdong Lin 166*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_SYSCLK, 167b1387078SMark Brown ARIZONA_CLK_SRC_FLL1, 168b1387078SMark Brown bells->sysclk_rate, 169b1387078SMark Brown SND_SOC_CLOCK_IN); 170b1387078SMark Brown if (ret != 0) { 171*f4a2be1cSKuninori Morimoto dev_err(component->dev, "Failed to set SYSCLK: %d\n", ret); 172b1387078SMark Brown return ret; 173b1387078SMark Brown } 174b1387078SMark Brown 175*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0); 176344c5edeSMark Brown if (ret != 0) { 177344c5edeSMark Brown dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret); 178344c5edeSMark Brown return ret; 179344c5edeSMark Brown } 180344c5edeSMark Brown 181b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); 182b1387078SMark Brown if (ret != 0) 183b545dd92SMark Brown dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); 184b1387078SMark Brown 185*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_OPCLK, 0, 186b1387078SMark Brown SYS_MCLK_RATE, SND_SOC_CLOCK_OUT); 187b1387078SMark Brown if (ret != 0) 188*f4a2be1cSKuninori Morimoto dev_err(component->dev, "Failed to set OPCLK: %d\n", ret); 189b1387078SMark Brown 190b1387078SMark Brown if (card->num_rtd == DAI_CODEC_CP) 191b1387078SMark Brown return 0; 192b1387078SMark Brown 193*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(component, ARIZONA_CLK_ASYNCCLK, 194b1387078SMark Brown ARIZONA_CLK_SRC_FLL2, 195b1387078SMark Brown bells->asyncclk_rate, 196b1387078SMark Brown SND_SOC_CLOCK_IN); 197b1387078SMark Brown if (ret != 0) { 198*f4a2be1cSKuninori Morimoto dev_err(component->dev, "Failed to set ASYNCCLK: %d\n", ret); 199b545dd92SMark Brown return ret; 200b545dd92SMark Brown } 201b545dd92SMark Brown 2025015920aSMengdong Lin rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_CP].name); 2035015920aSMengdong Lin aif2_dai = rtd->cpu_dai; 204b1387078SMark Brown 205b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); 206b545dd92SMark Brown if (ret != 0) { 207b545dd92SMark Brown dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); 208b545dd92SMark Brown return ret; 209b545dd92SMark Brown } 210b545dd92SMark Brown 211b1387078SMark Brown if (card->num_rtd == DAI_CODEC_SUB) 212b1387078SMark Brown return 0; 213b1387078SMark Brown 2145015920aSMengdong Lin rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_SUB].name); 2155015920aSMengdong Lin aif3_dai = rtd->cpu_dai; 2165015920aSMengdong Lin wm9081_dai = rtd->codec_dai; 217b1387078SMark Brown 218b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); 219b545dd92SMark Brown if (ret != 0) { 220b545dd92SMark Brown dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); 221b545dd92SMark Brown return ret; 222b545dd92SMark Brown } 223b545dd92SMark Brown 224*f4a2be1cSKuninori Morimoto ret = snd_soc_component_set_sysclk(wm9081_dai->component, WM9081_SYSCLK_MCLK, 225344c5edeSMark Brown 0, SYS_MCLK_RATE, 0); 226b545dd92SMark Brown if (ret != 0) { 227b545dd92SMark Brown dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); 228b545dd92SMark Brown return ret; 229b545dd92SMark Brown } 230b545dd92SMark Brown 231b545dd92SMark Brown return 0; 232b545dd92SMark Brown } 233b545dd92SMark Brown 234b545dd92SMark Brown static const struct snd_soc_pcm_stream baseband_params = { 235b545dd92SMark Brown .formats = SNDRV_PCM_FMTBIT_S32_LE, 236b545dd92SMark Brown .rate_min = 8000, 237b545dd92SMark Brown .rate_max = 8000, 238b545dd92SMark Brown .channels_min = 2, 239b545dd92SMark Brown .channels_max = 2, 240b545dd92SMark Brown }; 241b545dd92SMark Brown 242b545dd92SMark Brown static const struct snd_soc_pcm_stream sub_params = { 243b545dd92SMark Brown .formats = SNDRV_PCM_FMTBIT_S32_LE, 244344c5edeSMark Brown .rate_min = SYS_AUDIO_RATE, 245344c5edeSMark Brown .rate_max = SYS_AUDIO_RATE, 246b545dd92SMark Brown .channels_min = 2, 247b545dd92SMark Brown .channels_max = 2, 248b545dd92SMark Brown }; 249b545dd92SMark Brown 2508d47e8a5SMark Brown static struct snd_soc_dai_link bells_dai_wm2200[] = { 2518d47e8a5SMark Brown { 2528d47e8a5SMark Brown .name = "CPU-DSP", 2538d47e8a5SMark Brown .stream_name = "CPU-DSP", 2548d47e8a5SMark Brown .cpu_dai_name = "samsung-i2s.0", 2558d47e8a5SMark Brown .codec_dai_name = "wm0010-sdi1", 256a08485d8SPadmavathi Venna .platform_name = "samsung-i2s.0", 2578d47e8a5SMark Brown .codec_name = "spi0.0", 2588d47e8a5SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 2598d47e8a5SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 2608d47e8a5SMark Brown }, 2618d47e8a5SMark Brown { 2628d47e8a5SMark Brown .name = "DSP-CODEC", 2638d47e8a5SMark Brown .stream_name = "DSP-CODEC", 2648d47e8a5SMark Brown .cpu_dai_name = "wm0010-sdi2", 2658d47e8a5SMark Brown .codec_dai_name = "wm2200", 2668d47e8a5SMark Brown .codec_name = "wm2200.1-003a", 2678d47e8a5SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 2688d47e8a5SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 2698d47e8a5SMark Brown .params = &sub_params, 2708d47e8a5SMark Brown .ignore_suspend = 1, 2718d47e8a5SMark Brown }, 2728d47e8a5SMark Brown }; 2738d47e8a5SMark Brown 274b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5102[] = { 275b545dd92SMark Brown { 276344c5edeSMark Brown .name = "CPU-DSP", 277344c5edeSMark Brown .stream_name = "CPU-DSP", 278b545dd92SMark Brown .cpu_dai_name = "samsung-i2s.0", 279344c5edeSMark Brown .codec_dai_name = "wm0010-sdi1", 280a08485d8SPadmavathi Venna .platform_name = "samsung-i2s.0", 281344c5edeSMark Brown .codec_name = "spi0.0", 282344c5edeSMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 283344c5edeSMark Brown | SND_SOC_DAIFMT_CBM_CFM, 284344c5edeSMark Brown }, 285344c5edeSMark Brown { 286344c5edeSMark Brown .name = "DSP-CODEC", 287344c5edeSMark Brown .stream_name = "DSP-CODEC", 288344c5edeSMark Brown .cpu_dai_name = "wm0010-sdi2", 289344c5edeSMark Brown .codec_dai_name = "wm5102-aif1", 290b545dd92SMark Brown .codec_name = "wm5102-codec", 291b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 292b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 293344c5edeSMark Brown .params = &sub_params, 294344c5edeSMark Brown .ignore_suspend = 1, 295b545dd92SMark Brown }, 296b545dd92SMark Brown { 297b545dd92SMark Brown .name = "Baseband", 298b545dd92SMark Brown .stream_name = "Baseband", 299b545dd92SMark Brown .cpu_dai_name = "wm5102-aif2", 300b545dd92SMark Brown .codec_dai_name = "wm1250-ev1", 301b545dd92SMark Brown .codec_name = "wm1250-ev1.1-0027", 302b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 303b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 304b545dd92SMark Brown .ignore_suspend = 1, 305b545dd92SMark Brown .params = &baseband_params, 306b545dd92SMark Brown }, 307b545dd92SMark Brown { 308b545dd92SMark Brown .name = "Sub", 309b545dd92SMark Brown .stream_name = "Sub", 310b545dd92SMark Brown .cpu_dai_name = "wm5102-aif3", 311b545dd92SMark Brown .codec_dai_name = "wm9081-hifi", 312b545dd92SMark Brown .codec_name = "wm9081.1-006c", 313b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 314b545dd92SMark Brown | SND_SOC_DAIFMT_CBS_CFS, 315b545dd92SMark Brown .ignore_suspend = 1, 316b545dd92SMark Brown .params = &sub_params, 317b545dd92SMark Brown }, 318b545dd92SMark Brown }; 319b545dd92SMark Brown 320b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5110[] = { 321b545dd92SMark Brown { 322344c5edeSMark Brown .name = "CPU-DSP", 323344c5edeSMark Brown .stream_name = "CPU-DSP", 324b545dd92SMark Brown .cpu_dai_name = "samsung-i2s.0", 325344c5edeSMark Brown .codec_dai_name = "wm0010-sdi1", 326a08485d8SPadmavathi Venna .platform_name = "samsung-i2s.0", 327344c5edeSMark Brown .codec_name = "spi0.0", 328344c5edeSMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 329344c5edeSMark Brown | SND_SOC_DAIFMT_CBM_CFM, 330344c5edeSMark Brown }, 331344c5edeSMark Brown { 332344c5edeSMark Brown .name = "DSP-CODEC", 333344c5edeSMark Brown .stream_name = "DSP-CODEC", 334344c5edeSMark Brown .cpu_dai_name = "wm0010-sdi2", 335344c5edeSMark Brown .codec_dai_name = "wm5110-aif1", 336b545dd92SMark Brown .codec_name = "wm5110-codec", 337b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 338b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 339344c5edeSMark Brown .params = &sub_params, 340344c5edeSMark Brown .ignore_suspend = 1, 341b545dd92SMark Brown }, 342b545dd92SMark Brown { 343b545dd92SMark Brown .name = "Baseband", 344b545dd92SMark Brown .stream_name = "Baseband", 345b545dd92SMark Brown .cpu_dai_name = "wm5110-aif2", 346b545dd92SMark Brown .codec_dai_name = "wm1250-ev1", 347b545dd92SMark Brown .codec_name = "wm1250-ev1.1-0027", 348b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 349b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 350b545dd92SMark Brown .ignore_suspend = 1, 351b545dd92SMark Brown .params = &baseband_params, 352b545dd92SMark Brown }, 353b545dd92SMark Brown { 354b545dd92SMark Brown .name = "Sub", 355b545dd92SMark Brown .stream_name = "Sub", 356ffaa839bSMark Brown .cpu_dai_name = "wm5110-aif3", 357b545dd92SMark Brown .codec_dai_name = "wm9081-hifi", 358b545dd92SMark Brown .codec_name = "wm9081.1-006c", 359b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 360b545dd92SMark Brown | SND_SOC_DAIFMT_CBS_CFS, 361b545dd92SMark Brown .ignore_suspend = 1, 362b545dd92SMark Brown .params = &sub_params, 363b545dd92SMark Brown }, 364b545dd92SMark Brown }; 365b545dd92SMark Brown 366b545dd92SMark Brown static struct snd_soc_codec_conf bells_codec_conf[] = { 367b545dd92SMark Brown { 368b545dd92SMark Brown .dev_name = "wm9081.1-006c", 369b545dd92SMark Brown .name_prefix = "Sub", 370b545dd92SMark Brown }, 371b545dd92SMark Brown }; 372b545dd92SMark Brown 373939d3c6aSCharles Keepax static struct snd_soc_dapm_widget bells_widgets[] = { 374939d3c6aSCharles Keepax SND_SOC_DAPM_MIC("DMIC", NULL), 375939d3c6aSCharles Keepax }; 376939d3c6aSCharles Keepax 377b545dd92SMark Brown static struct snd_soc_dapm_route bells_routes[] = { 378b545dd92SMark Brown { "Sub CLK_SYS", NULL, "OPCLK" }, 379b3a6006eSCharles Keepax { "CLKIN", NULL, "OPCLK" }, 380939d3c6aSCharles Keepax 381939d3c6aSCharles Keepax { "DMIC", NULL, "MICBIAS2" }, 382939d3c6aSCharles Keepax { "IN2L", NULL, "DMIC" }, 383939d3c6aSCharles Keepax { "IN2R", NULL, "DMIC" }, 384b545dd92SMark Brown }; 385b545dd92SMark Brown 386b545dd92SMark Brown static struct snd_soc_card bells_cards[] = { 387b545dd92SMark Brown { 3888d47e8a5SMark Brown .name = "Bells WM2200", 3898d47e8a5SMark Brown .owner = THIS_MODULE, 3908d47e8a5SMark Brown .dai_link = bells_dai_wm2200, 3918d47e8a5SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm2200), 3928d47e8a5SMark Brown .codec_conf = bells_codec_conf, 3938d47e8a5SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 3948d47e8a5SMark Brown 3958d47e8a5SMark Brown .late_probe = bells_late_probe, 3968d47e8a5SMark Brown 397939d3c6aSCharles Keepax .dapm_widgets = bells_widgets, 398939d3c6aSCharles Keepax .num_dapm_widgets = ARRAY_SIZE(bells_widgets), 3998d47e8a5SMark Brown .dapm_routes = bells_routes, 4008d47e8a5SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 4018d47e8a5SMark Brown 4028d47e8a5SMark Brown .set_bias_level = bells_set_bias_level, 4038d47e8a5SMark Brown .set_bias_level_post = bells_set_bias_level_post, 4048d47e8a5SMark Brown 4058d47e8a5SMark Brown .drvdata = &wm2200_drvdata, 4068d47e8a5SMark Brown }, 4078d47e8a5SMark Brown { 408b545dd92SMark Brown .name = "Bells WM5102", 409b545dd92SMark Brown .owner = THIS_MODULE, 410b545dd92SMark Brown .dai_link = bells_dai_wm5102, 411b545dd92SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm5102), 412b545dd92SMark Brown .codec_conf = bells_codec_conf, 413b545dd92SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 414b545dd92SMark Brown 415b545dd92SMark Brown .late_probe = bells_late_probe, 416b545dd92SMark Brown 417939d3c6aSCharles Keepax .dapm_widgets = bells_widgets, 418939d3c6aSCharles Keepax .num_dapm_widgets = ARRAY_SIZE(bells_widgets), 419b545dd92SMark Brown .dapm_routes = bells_routes, 420b545dd92SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 421b545dd92SMark Brown 422b545dd92SMark Brown .set_bias_level = bells_set_bias_level, 423b545dd92SMark Brown .set_bias_level_post = bells_set_bias_level_post, 424b1387078SMark Brown 425b1387078SMark Brown .drvdata = &wm5102_drvdata, 426b545dd92SMark Brown }, 427b545dd92SMark Brown { 428b545dd92SMark Brown .name = "Bells WM5110", 429b545dd92SMark Brown .owner = THIS_MODULE, 430b545dd92SMark Brown .dai_link = bells_dai_wm5110, 431b545dd92SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm5110), 432b545dd92SMark Brown .codec_conf = bells_codec_conf, 433b545dd92SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 434b545dd92SMark Brown 435b545dd92SMark Brown .late_probe = bells_late_probe, 436b545dd92SMark Brown 437939d3c6aSCharles Keepax .dapm_widgets = bells_widgets, 438939d3c6aSCharles Keepax .num_dapm_widgets = ARRAY_SIZE(bells_widgets), 439b545dd92SMark Brown .dapm_routes = bells_routes, 440b545dd92SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 441b545dd92SMark Brown 442b545dd92SMark Brown .set_bias_level = bells_set_bias_level, 443b545dd92SMark Brown .set_bias_level_post = bells_set_bias_level_post, 444b1387078SMark Brown 445b1387078SMark Brown .drvdata = &wm5110_drvdata, 446b545dd92SMark Brown }, 447b545dd92SMark Brown }; 448b545dd92SMark Brown 449fdca21adSBill Pemberton static int bells_probe(struct platform_device *pdev) 450b545dd92SMark Brown { 451b545dd92SMark Brown int ret; 452b545dd92SMark Brown 453b545dd92SMark Brown bells_cards[pdev->id].dev = &pdev->dev; 454b545dd92SMark Brown 455c583883eSTushar Behera ret = devm_snd_soc_register_card(&pdev->dev, &bells_cards[pdev->id]); 456c583883eSTushar Behera if (ret) 457b545dd92SMark Brown dev_err(&pdev->dev, 458b545dd92SMark Brown "snd_soc_register_card(%s) failed: %d\n", 459b545dd92SMark Brown bells_cards[pdev->id].name, ret); 460c583883eSTushar Behera 461b545dd92SMark Brown return ret; 462b545dd92SMark Brown } 463b545dd92SMark Brown 464b545dd92SMark Brown static struct platform_driver bells_driver = { 465b545dd92SMark Brown .driver = { 466b545dd92SMark Brown .name = "bells", 467b545dd92SMark Brown .pm = &snd_soc_pm_ops, 468b545dd92SMark Brown }, 469b545dd92SMark Brown .probe = bells_probe, 470b545dd92SMark Brown }; 471b545dd92SMark Brown 472b545dd92SMark Brown module_platform_driver(bells_driver); 473b545dd92SMark Brown 474b545dd92SMark Brown MODULE_DESCRIPTION("Bells audio support"); 475b545dd92SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 476b545dd92SMark Brown MODULE_LICENSE("GPL"); 477b545dd92SMark Brown MODULE_ALIAS("platform:bells"); 478