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 31344c5edeSMark Brown #define SYS_MCLK_RATE (SYS_AUDIO_RATE * 256) 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 43*8d47e8a5SMark Brown static struct bells_drvdata wm2200_drvdata = { 44*8d47e8a5SMark Brown .sysclk_rate = 22579200, 45*8d47e8a5SMark Brown }; 46*8d47e8a5SMark 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 { 61344c5edeSMark Brown struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; 62b545dd92SMark Brown struct snd_soc_codec *codec = codec_dai->codec; 63b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 64b545dd92SMark Brown int ret; 65b545dd92SMark Brown 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 74b545dd92SMark Brown ret = snd_soc_codec_set_pll(codec, 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) { 82b545dd92SMark Brown ret = snd_soc_codec_set_pll(codec, 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 { 102344c5edeSMark Brown struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; 103b545dd92SMark Brown struct snd_soc_codec *codec = codec_dai->codec; 104b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 105b545dd92SMark Brown int ret; 106b545dd92SMark Brown 107b545dd92SMark Brown if (dapm->dev != codec_dai->dev) 108b545dd92SMark Brown return 0; 109b545dd92SMark Brown 110b545dd92SMark Brown switch (level) { 111b545dd92SMark Brown case SND_SOC_BIAS_STANDBY: 112b545dd92SMark Brown ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0); 113b545dd92SMark Brown if (ret < 0) { 114b545dd92SMark Brown pr_err("Failed to stop FLL: %d\n", ret); 115b545dd92SMark Brown return ret; 116b545dd92SMark Brown } 117b545dd92SMark Brown 118b1387078SMark Brown if (bells->asyncclk_rate) { 119b1387078SMark Brown ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, 120b1387078SMark Brown 0, 0, 0); 121b545dd92SMark Brown if (ret < 0) { 122b545dd92SMark Brown pr_err("Failed to stop FLL: %d\n", ret); 123b545dd92SMark Brown return ret; 124b545dd92SMark Brown } 125b1387078SMark Brown } 126b545dd92SMark Brown break; 127b545dd92SMark Brown 128b545dd92SMark Brown default: 129b545dd92SMark Brown break; 130b545dd92SMark Brown } 131b545dd92SMark Brown 132b545dd92SMark Brown dapm->bias_level = level; 133b545dd92SMark Brown 134b545dd92SMark Brown return 0; 135b545dd92SMark Brown } 136b545dd92SMark Brown 137b545dd92SMark Brown static int bells_late_probe(struct snd_soc_card *card) 138b545dd92SMark Brown { 139b1387078SMark Brown struct bells_drvdata *bells = card->drvdata; 140344c5edeSMark Brown struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec; 141344c5edeSMark Brown struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec; 142344c5edeSMark Brown struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai; 143b1387078SMark Brown struct snd_soc_dai *aif2_dai; 144b1387078SMark Brown struct snd_soc_dai *aif3_dai; 145b1387078SMark Brown struct snd_soc_dai *wm9081_dai; 146b545dd92SMark Brown int ret; 147b545dd92SMark Brown 148b1387078SMark Brown ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, 149b1387078SMark Brown ARIZONA_CLK_SRC_FLL1, 150b1387078SMark Brown bells->sysclk_rate, 151b1387078SMark Brown SND_SOC_CLOCK_IN); 152b1387078SMark Brown if (ret != 0) { 153b1387078SMark Brown dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); 154b1387078SMark Brown return ret; 155b1387078SMark Brown } 156b1387078SMark Brown 157344c5edeSMark Brown ret = snd_soc_codec_set_sysclk(wm0010, 0, 0, SYS_MCLK_RATE, 0); 158344c5edeSMark Brown if (ret != 0) { 159344c5edeSMark Brown dev_err(wm0010->dev, "Failed to set WM0010 clock: %d\n", ret); 160344c5edeSMark Brown return ret; 161344c5edeSMark Brown } 162344c5edeSMark Brown 163b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); 164b1387078SMark Brown if (ret != 0) 165b545dd92SMark Brown dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); 166b1387078SMark Brown 167b1387078SMark Brown ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0, 168b1387078SMark Brown SYS_MCLK_RATE, SND_SOC_CLOCK_OUT); 169b1387078SMark Brown if (ret != 0) 170b1387078SMark Brown dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret); 171b1387078SMark Brown 172b1387078SMark Brown if (card->num_rtd == DAI_CODEC_CP) 173b1387078SMark Brown return 0; 174b1387078SMark Brown 175b1387078SMark Brown ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, 176b1387078SMark Brown ARIZONA_CLK_SRC_FLL2, 177b1387078SMark Brown bells->asyncclk_rate, 178b1387078SMark Brown SND_SOC_CLOCK_IN); 179b1387078SMark Brown if (ret != 0) { 180b1387078SMark Brown dev_err(codec->dev, "Failed to set ASYNCCLK: %d\n", ret); 181b545dd92SMark Brown return ret; 182b545dd92SMark Brown } 183b545dd92SMark Brown 184b1387078SMark Brown aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai; 185b1387078SMark Brown 186b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); 187b545dd92SMark Brown if (ret != 0) { 188b545dd92SMark Brown dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret); 189b545dd92SMark Brown return ret; 190b545dd92SMark Brown } 191b545dd92SMark Brown 192b1387078SMark Brown if (card->num_rtd == DAI_CODEC_SUB) 193b1387078SMark Brown return 0; 194b1387078SMark Brown 195b1387078SMark Brown aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai; 196b1387078SMark Brown wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai; 197b1387078SMark Brown 198b545dd92SMark Brown ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); 199b545dd92SMark Brown if (ret != 0) { 200b545dd92SMark Brown dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret); 201b545dd92SMark Brown return ret; 202b545dd92SMark Brown } 203b545dd92SMark Brown 204b545dd92SMark Brown ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK, 205344c5edeSMark Brown 0, SYS_MCLK_RATE, 0); 206b545dd92SMark Brown if (ret != 0) { 207b545dd92SMark Brown dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret); 208b545dd92SMark Brown return ret; 209b545dd92SMark Brown } 210b545dd92SMark Brown 211b545dd92SMark Brown return 0; 212b545dd92SMark Brown } 213b545dd92SMark Brown 214b545dd92SMark Brown static const struct snd_soc_pcm_stream baseband_params = { 215b545dd92SMark Brown .formats = SNDRV_PCM_FMTBIT_S32_LE, 216b545dd92SMark Brown .rate_min = 8000, 217b545dd92SMark Brown .rate_max = 8000, 218b545dd92SMark Brown .channels_min = 2, 219b545dd92SMark Brown .channels_max = 2, 220b545dd92SMark Brown }; 221b545dd92SMark Brown 222b545dd92SMark Brown static const struct snd_soc_pcm_stream sub_params = { 223b545dd92SMark Brown .formats = SNDRV_PCM_FMTBIT_S32_LE, 224344c5edeSMark Brown .rate_min = SYS_AUDIO_RATE, 225344c5edeSMark Brown .rate_max = SYS_AUDIO_RATE, 226b545dd92SMark Brown .channels_min = 2, 227b545dd92SMark Brown .channels_max = 2, 228b545dd92SMark Brown }; 229b545dd92SMark Brown 230*8d47e8a5SMark Brown static struct snd_soc_dai_link bells_dai_wm2200[] = { 231*8d47e8a5SMark Brown { 232*8d47e8a5SMark Brown .name = "CPU-DSP", 233*8d47e8a5SMark Brown .stream_name = "CPU-DSP", 234*8d47e8a5SMark Brown .cpu_dai_name = "samsung-i2s.0", 235*8d47e8a5SMark Brown .codec_dai_name = "wm0010-sdi1", 236*8d47e8a5SMark Brown .platform_name = "samsung-audio", 237*8d47e8a5SMark Brown .codec_name = "spi0.0", 238*8d47e8a5SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 239*8d47e8a5SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 240*8d47e8a5SMark Brown }, 241*8d47e8a5SMark Brown { 242*8d47e8a5SMark Brown .name = "DSP-CODEC", 243*8d47e8a5SMark Brown .stream_name = "DSP-CODEC", 244*8d47e8a5SMark Brown .cpu_dai_name = "wm0010-sdi2", 245*8d47e8a5SMark Brown .codec_dai_name = "wm2200", 246*8d47e8a5SMark Brown .codec_name = "wm2200.1-003a", 247*8d47e8a5SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 248*8d47e8a5SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 249*8d47e8a5SMark Brown .params = &sub_params, 250*8d47e8a5SMark Brown .ignore_suspend = 1, 251*8d47e8a5SMark Brown }, 252*8d47e8a5SMark Brown }; 253*8d47e8a5SMark Brown 254b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5102[] = { 255b545dd92SMark Brown { 256344c5edeSMark Brown .name = "CPU-DSP", 257344c5edeSMark Brown .stream_name = "CPU-DSP", 258b545dd92SMark Brown .cpu_dai_name = "samsung-i2s.0", 259344c5edeSMark Brown .codec_dai_name = "wm0010-sdi1", 260b545dd92SMark Brown .platform_name = "samsung-audio", 261344c5edeSMark Brown .codec_name = "spi0.0", 262344c5edeSMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 263344c5edeSMark Brown | SND_SOC_DAIFMT_CBM_CFM, 264344c5edeSMark Brown }, 265344c5edeSMark Brown { 266344c5edeSMark Brown .name = "DSP-CODEC", 267344c5edeSMark Brown .stream_name = "DSP-CODEC", 268344c5edeSMark Brown .cpu_dai_name = "wm0010-sdi2", 269344c5edeSMark Brown .codec_dai_name = "wm5102-aif1", 270b545dd92SMark Brown .codec_name = "wm5102-codec", 271b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 272b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 273344c5edeSMark Brown .params = &sub_params, 274344c5edeSMark Brown .ignore_suspend = 1, 275b545dd92SMark Brown }, 276b545dd92SMark Brown { 277b545dd92SMark Brown .name = "Baseband", 278b545dd92SMark Brown .stream_name = "Baseband", 279b545dd92SMark Brown .cpu_dai_name = "wm5102-aif2", 280b545dd92SMark Brown .codec_dai_name = "wm1250-ev1", 281b545dd92SMark Brown .codec_name = "wm1250-ev1.1-0027", 282b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 283b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 284b545dd92SMark Brown .ignore_suspend = 1, 285b545dd92SMark Brown .params = &baseband_params, 286b545dd92SMark Brown }, 287b545dd92SMark Brown { 288b545dd92SMark Brown .name = "Sub", 289b545dd92SMark Brown .stream_name = "Sub", 290b545dd92SMark Brown .cpu_dai_name = "wm5102-aif3", 291b545dd92SMark Brown .codec_dai_name = "wm9081-hifi", 292b545dd92SMark Brown .codec_name = "wm9081.1-006c", 293b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 294b545dd92SMark Brown | SND_SOC_DAIFMT_CBS_CFS, 295b545dd92SMark Brown .ignore_suspend = 1, 296b545dd92SMark Brown .params = &sub_params, 297b545dd92SMark Brown }, 298b545dd92SMark Brown }; 299b545dd92SMark Brown 300b545dd92SMark Brown static struct snd_soc_dai_link bells_dai_wm5110[] = { 301b545dd92SMark Brown { 302344c5edeSMark Brown .name = "CPU-DSP", 303344c5edeSMark Brown .stream_name = "CPU-DSP", 304b545dd92SMark Brown .cpu_dai_name = "samsung-i2s.0", 305344c5edeSMark Brown .codec_dai_name = "wm0010-sdi1", 306b545dd92SMark Brown .platform_name = "samsung-audio", 307344c5edeSMark Brown .codec_name = "spi0.0", 308344c5edeSMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 309344c5edeSMark Brown | SND_SOC_DAIFMT_CBM_CFM, 310344c5edeSMark Brown }, 311344c5edeSMark Brown { 312344c5edeSMark Brown .name = "DSP-CODEC", 313344c5edeSMark Brown .stream_name = "DSP-CODEC", 314344c5edeSMark Brown .cpu_dai_name = "wm0010-sdi2", 315344c5edeSMark Brown .codec_dai_name = "wm5110-aif1", 316b545dd92SMark Brown .codec_name = "wm5110-codec", 317b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 318b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 319344c5edeSMark Brown .params = &sub_params, 320344c5edeSMark Brown .ignore_suspend = 1, 321b545dd92SMark Brown }, 322b545dd92SMark Brown { 323b545dd92SMark Brown .name = "Baseband", 324b545dd92SMark Brown .stream_name = "Baseband", 325b545dd92SMark Brown .cpu_dai_name = "wm5110-aif2", 326b545dd92SMark Brown .codec_dai_name = "wm1250-ev1", 327b545dd92SMark Brown .codec_name = "wm1250-ev1.1-0027", 328b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 329b545dd92SMark Brown | SND_SOC_DAIFMT_CBM_CFM, 330b545dd92SMark Brown .ignore_suspend = 1, 331b545dd92SMark Brown .params = &baseband_params, 332b545dd92SMark Brown }, 333b545dd92SMark Brown { 334b545dd92SMark Brown .name = "Sub", 335b545dd92SMark Brown .stream_name = "Sub", 336ffaa839bSMark Brown .cpu_dai_name = "wm5110-aif3", 337b545dd92SMark Brown .codec_dai_name = "wm9081-hifi", 338b545dd92SMark Brown .codec_name = "wm9081.1-006c", 339b545dd92SMark Brown .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 340b545dd92SMark Brown | SND_SOC_DAIFMT_CBS_CFS, 341b545dd92SMark Brown .ignore_suspend = 1, 342b545dd92SMark Brown .params = &sub_params, 343b545dd92SMark Brown }, 344b545dd92SMark Brown }; 345b545dd92SMark Brown 346b545dd92SMark Brown static struct snd_soc_codec_conf bells_codec_conf[] = { 347b545dd92SMark Brown { 348b545dd92SMark Brown .dev_name = "wm9081.1-006c", 349b545dd92SMark Brown .name_prefix = "Sub", 350b545dd92SMark Brown }, 351b545dd92SMark Brown }; 352b545dd92SMark Brown 353b545dd92SMark Brown static struct snd_soc_dapm_route bells_routes[] = { 354b545dd92SMark Brown { "Sub CLK_SYS", NULL, "OPCLK" }, 355b545dd92SMark Brown }; 356b545dd92SMark Brown 357b545dd92SMark Brown static struct snd_soc_card bells_cards[] = { 358b545dd92SMark Brown { 359*8d47e8a5SMark Brown .name = "Bells WM2200", 360*8d47e8a5SMark Brown .owner = THIS_MODULE, 361*8d47e8a5SMark Brown .dai_link = bells_dai_wm2200, 362*8d47e8a5SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm2200), 363*8d47e8a5SMark Brown .codec_conf = bells_codec_conf, 364*8d47e8a5SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 365*8d47e8a5SMark Brown 366*8d47e8a5SMark Brown .late_probe = bells_late_probe, 367*8d47e8a5SMark Brown 368*8d47e8a5SMark Brown .dapm_routes = bells_routes, 369*8d47e8a5SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 370*8d47e8a5SMark Brown 371*8d47e8a5SMark Brown .set_bias_level = bells_set_bias_level, 372*8d47e8a5SMark Brown .set_bias_level_post = bells_set_bias_level_post, 373*8d47e8a5SMark Brown 374*8d47e8a5SMark Brown .drvdata = &wm2200_drvdata, 375*8d47e8a5SMark Brown }, 376*8d47e8a5SMark Brown { 377b545dd92SMark Brown .name = "Bells WM5102", 378b545dd92SMark Brown .owner = THIS_MODULE, 379b545dd92SMark Brown .dai_link = bells_dai_wm5102, 380b545dd92SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm5102), 381b545dd92SMark Brown .codec_conf = bells_codec_conf, 382b545dd92SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 383b545dd92SMark Brown 384b545dd92SMark Brown .late_probe = bells_late_probe, 385b545dd92SMark Brown 386b545dd92SMark Brown .dapm_routes = bells_routes, 387b545dd92SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 388b545dd92SMark Brown 389b545dd92SMark Brown .set_bias_level = bells_set_bias_level, 390b545dd92SMark Brown .set_bias_level_post = bells_set_bias_level_post, 391b1387078SMark Brown 392b1387078SMark Brown .drvdata = &wm5102_drvdata, 393b545dd92SMark Brown }, 394b545dd92SMark Brown { 395b545dd92SMark Brown .name = "Bells WM5110", 396b545dd92SMark Brown .owner = THIS_MODULE, 397b545dd92SMark Brown .dai_link = bells_dai_wm5110, 398b545dd92SMark Brown .num_links = ARRAY_SIZE(bells_dai_wm5110), 399b545dd92SMark Brown .codec_conf = bells_codec_conf, 400b545dd92SMark Brown .num_configs = ARRAY_SIZE(bells_codec_conf), 401b545dd92SMark Brown 402b545dd92SMark Brown .late_probe = bells_late_probe, 403b545dd92SMark Brown 404b545dd92SMark Brown .dapm_routes = bells_routes, 405b545dd92SMark Brown .num_dapm_routes = ARRAY_SIZE(bells_routes), 406b545dd92SMark Brown 407b545dd92SMark Brown .set_bias_level = bells_set_bias_level, 408b545dd92SMark Brown .set_bias_level_post = bells_set_bias_level_post, 409b1387078SMark Brown 410b1387078SMark Brown .drvdata = &wm5110_drvdata, 411b545dd92SMark Brown }, 412b545dd92SMark Brown }; 413b545dd92SMark Brown 414b545dd92SMark Brown 415b545dd92SMark Brown static __devinit int bells_probe(struct platform_device *pdev) 416b545dd92SMark Brown { 417b545dd92SMark Brown int ret; 418b545dd92SMark Brown 419b545dd92SMark Brown bells_cards[pdev->id].dev = &pdev->dev; 420b545dd92SMark Brown 421b545dd92SMark Brown ret = snd_soc_register_card(&bells_cards[pdev->id]); 422b545dd92SMark Brown if (ret) { 423b545dd92SMark Brown dev_err(&pdev->dev, 424b545dd92SMark Brown "snd_soc_register_card(%s) failed: %d\n", 425b545dd92SMark Brown bells_cards[pdev->id].name, ret); 426b545dd92SMark Brown return ret; 427b545dd92SMark Brown } 428b545dd92SMark Brown 429b545dd92SMark Brown return 0; 430b545dd92SMark Brown } 431b545dd92SMark Brown 432b545dd92SMark Brown static int __devexit bells_remove(struct platform_device *pdev) 433b545dd92SMark Brown { 434b545dd92SMark Brown snd_soc_unregister_card(&bells_cards[pdev->id]); 435b545dd92SMark Brown 436b545dd92SMark Brown return 0; 437b545dd92SMark Brown } 438b545dd92SMark Brown 439b545dd92SMark Brown static struct platform_driver bells_driver = { 440b545dd92SMark Brown .driver = { 441b545dd92SMark Brown .name = "bells", 442b545dd92SMark Brown .owner = THIS_MODULE, 443b545dd92SMark Brown .pm = &snd_soc_pm_ops, 444b545dd92SMark Brown }, 445b545dd92SMark Brown .probe = bells_probe, 446b545dd92SMark Brown .remove = __devexit_p(bells_remove), 447b545dd92SMark Brown }; 448b545dd92SMark Brown 449b545dd92SMark Brown module_platform_driver(bells_driver); 450b545dd92SMark Brown 451b545dd92SMark Brown MODULE_DESCRIPTION("Bells audio support"); 452b545dd92SMark Brown MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 453b545dd92SMark Brown MODULE_LICENSE("GPL"); 454b545dd92SMark Brown MODULE_ALIAS("platform:bells"); 455