1 // SPDX-License-Identifier: GPL-2.0+ 2 // 3 // Littlemill audio support 4 // 5 // Copyright 2011 Wolfson Microelectronics 6 7 #include <sound/soc.h> 8 #include <sound/soc-dapm.h> 9 #include <sound/jack.h> 10 #include <linux/gpio.h> 11 #include <linux/module.h> 12 13 #include "../codecs/wm8994.h" 14 15 static int sample_rate = 44100; 16 17 static int littlemill_set_bias_level(struct snd_soc_card *card, 18 struct snd_soc_dapm_context *dapm, 19 enum snd_soc_bias_level level) 20 { 21 struct snd_soc_pcm_runtime *rtd; 22 struct snd_soc_dai *aif1_dai; 23 int ret; 24 25 rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]); 26 aif1_dai = asoc_rtd_to_codec(rtd, 0); 27 28 if (dapm->dev != aif1_dai->dev) 29 return 0; 30 31 switch (level) { 32 case SND_SOC_BIAS_PREPARE: 33 /* 34 * If we've not already clocked things via hw_params() 35 * then do so now, otherwise these are noops. 36 */ 37 if (dapm->bias_level == SND_SOC_BIAS_STANDBY) { 38 ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1, 39 WM8994_FLL_SRC_MCLK2, 32768, 40 sample_rate * 512); 41 if (ret < 0) { 42 pr_err("Failed to start FLL: %d\n", ret); 43 return ret; 44 } 45 46 ret = snd_soc_dai_set_sysclk(aif1_dai, 47 WM8994_SYSCLK_FLL1, 48 sample_rate * 512, 49 SND_SOC_CLOCK_IN); 50 if (ret < 0) { 51 pr_err("Failed to set SYSCLK: %d\n", ret); 52 return ret; 53 } 54 } 55 break; 56 57 default: 58 break; 59 } 60 61 return 0; 62 } 63 64 static int littlemill_set_bias_level_post(struct snd_soc_card *card, 65 struct snd_soc_dapm_context *dapm, 66 enum snd_soc_bias_level level) 67 { 68 struct snd_soc_pcm_runtime *rtd; 69 struct snd_soc_dai *aif1_dai; 70 int ret; 71 72 rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]); 73 aif1_dai = asoc_rtd_to_codec(rtd, 0); 74 75 if (dapm->dev != aif1_dai->dev) 76 return 0; 77 78 switch (level) { 79 case SND_SOC_BIAS_STANDBY: 80 ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, 81 32768, SND_SOC_CLOCK_IN); 82 if (ret < 0) { 83 pr_err("Failed to switch away from FLL1: %d\n", ret); 84 return ret; 85 } 86 87 ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1, 88 0, 0, 0); 89 if (ret < 0) { 90 pr_err("Failed to stop FLL1: %d\n", ret); 91 return ret; 92 } 93 break; 94 95 default: 96 break; 97 } 98 99 dapm->bias_level = level; 100 101 return 0; 102 } 103 104 static int littlemill_hw_params(struct snd_pcm_substream *substream, 105 struct snd_pcm_hw_params *params) 106 { 107 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 108 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 109 int ret; 110 111 sample_rate = params_rate(params); 112 113 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, 114 WM8994_FLL_SRC_MCLK2, 32768, 115 sample_rate * 512); 116 if (ret < 0) { 117 pr_err("Failed to start FLL: %d\n", ret); 118 return ret; 119 } 120 121 ret = snd_soc_dai_set_sysclk(codec_dai, 122 WM8994_SYSCLK_FLL1, 123 sample_rate * 512, 124 SND_SOC_CLOCK_IN); 125 if (ret < 0) { 126 pr_err("Failed to set SYSCLK: %d\n", ret); 127 return ret; 128 } 129 130 return 0; 131 } 132 133 static const struct snd_soc_ops littlemill_ops = { 134 .hw_params = littlemill_hw_params, 135 }; 136 137 static const struct snd_soc_pcm_stream baseband_params = { 138 .formats = SNDRV_PCM_FMTBIT_S32_LE, 139 .rate_min = 8000, 140 .rate_max = 8000, 141 .channels_min = 2, 142 .channels_max = 2, 143 }; 144 145 SND_SOC_DAILINK_DEFS(cpu, 146 DAILINK_COMP_ARRAY(COMP_CPU("samsung-i2s.0")), 147 DAILINK_COMP_ARRAY(COMP_CODEC("wm8994-codec", "wm8994-aif1")), 148 DAILINK_COMP_ARRAY(COMP_PLATFORM("samsung-i2s.0"))); 149 150 SND_SOC_DAILINK_DEFS(baseband, 151 DAILINK_COMP_ARRAY(COMP_CPU("wm8994-aif2")), 152 DAILINK_COMP_ARRAY(COMP_CODEC("wm1250-ev1.1-0027", 153 "wm1250-ev1"))); 154 155 static struct snd_soc_dai_link littlemill_dai[] = { 156 { 157 .name = "CPU", 158 .stream_name = "CPU", 159 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 160 | SND_SOC_DAIFMT_CBM_CFM, 161 .ops = &littlemill_ops, 162 SND_SOC_DAILINK_REG(cpu), 163 }, 164 { 165 .name = "Baseband", 166 .stream_name = "Baseband", 167 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 168 | SND_SOC_DAIFMT_CBM_CFM, 169 .ignore_suspend = 1, 170 .c2c_params = &baseband_params, 171 .num_c2c_params = 1, 172 SND_SOC_DAILINK_REG(baseband), 173 }, 174 }; 175 176 static int bbclk_ev(struct snd_soc_dapm_widget *w, 177 struct snd_kcontrol *kcontrol, int event) 178 { 179 struct snd_soc_card *card = w->dapm->card; 180 struct snd_soc_pcm_runtime *rtd; 181 struct snd_soc_dai *aif2_dai; 182 int ret; 183 184 rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]); 185 aif2_dai = asoc_rtd_to_cpu(rtd, 0); 186 187 switch (event) { 188 case SND_SOC_DAPM_PRE_PMU: 189 ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2, 190 WM8994_FLL_SRC_BCLK, 64 * 8000, 191 8000 * 256); 192 if (ret < 0) { 193 pr_err("Failed to start FLL: %d\n", ret); 194 return ret; 195 } 196 197 ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_FLL2, 198 8000 * 256, 199 SND_SOC_CLOCK_IN); 200 if (ret < 0) { 201 pr_err("Failed to set SYSCLK: %d\n", ret); 202 return ret; 203 } 204 break; 205 case SND_SOC_DAPM_POST_PMD: 206 ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2, 207 32768, SND_SOC_CLOCK_IN); 208 if (ret < 0) { 209 pr_err("Failed to switch away from FLL2: %d\n", ret); 210 return ret; 211 } 212 213 ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2, 214 0, 0, 0); 215 if (ret < 0) { 216 pr_err("Failed to stop FLL2: %d\n", ret); 217 return ret; 218 } 219 break; 220 default: 221 return -EINVAL; 222 } 223 224 return 0; 225 } 226 227 static const struct snd_kcontrol_new controls[] = { 228 SOC_DAPM_PIN_SWITCH("WM1250 Input"), 229 SOC_DAPM_PIN_SWITCH("WM1250 Output"), 230 }; 231 232 static const struct snd_soc_dapm_widget widgets[] = { 233 SND_SOC_DAPM_HP("Headphone", NULL), 234 235 SND_SOC_DAPM_MIC("AMIC", NULL), 236 SND_SOC_DAPM_MIC("DMIC", NULL), 237 238 SND_SOC_DAPM_SUPPLY_S("Baseband Clock", -1, SND_SOC_NOPM, 0, 0, 239 bbclk_ev, 240 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 241 }; 242 243 static const struct snd_soc_dapm_route audio_paths[] = { 244 { "Headphone", NULL, "HPOUT1L" }, 245 { "Headphone", NULL, "HPOUT1R" }, 246 247 { "AMIC", NULL, "MICBIAS1" }, /* Default for AMICBIAS jumper */ 248 { "IN1LN", NULL, "AMIC" }, 249 250 { "DMIC", NULL, "MICBIAS2" }, /* Default for DMICBIAS jumper */ 251 { "DMIC1DAT", NULL, "DMIC" }, 252 { "DMIC2DAT", NULL, "DMIC" }, 253 254 { "AIF2CLK", NULL, "Baseband Clock" }, 255 }; 256 257 static struct snd_soc_jack littlemill_headset; 258 259 static int littlemill_late_probe(struct snd_soc_card *card) 260 { 261 struct snd_soc_pcm_runtime *rtd; 262 struct snd_soc_component *component; 263 struct snd_soc_dai *aif1_dai; 264 struct snd_soc_dai *aif2_dai; 265 int ret; 266 267 rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]); 268 component = asoc_rtd_to_codec(rtd, 0)->component; 269 aif1_dai = asoc_rtd_to_codec(rtd, 0); 270 271 rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[1]); 272 aif2_dai = asoc_rtd_to_cpu(rtd, 0); 273 274 ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, 275 32768, SND_SOC_CLOCK_IN); 276 if (ret < 0) 277 return ret; 278 279 ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2, 280 32768, SND_SOC_CLOCK_IN); 281 if (ret < 0) 282 return ret; 283 284 ret = snd_soc_card_jack_new(card, "Headset", 285 SND_JACK_HEADSET | SND_JACK_MECHANICAL | 286 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 287 SND_JACK_BTN_2 | SND_JACK_BTN_3 | 288 SND_JACK_BTN_4 | SND_JACK_BTN_5, 289 &littlemill_headset); 290 if (ret) 291 return ret; 292 293 /* This will check device compatibility itself */ 294 wm8958_mic_detect(component, &littlemill_headset, NULL, NULL, NULL, NULL); 295 296 /* As will this */ 297 wm8994_mic_detect(component, &littlemill_headset, 1); 298 299 return 0; 300 } 301 302 static struct snd_soc_card littlemill = { 303 .name = "Littlemill", 304 .owner = THIS_MODULE, 305 .dai_link = littlemill_dai, 306 .num_links = ARRAY_SIZE(littlemill_dai), 307 308 .set_bias_level = littlemill_set_bias_level, 309 .set_bias_level_post = littlemill_set_bias_level_post, 310 311 .controls = controls, 312 .num_controls = ARRAY_SIZE(controls), 313 .dapm_widgets = widgets, 314 .num_dapm_widgets = ARRAY_SIZE(widgets), 315 .dapm_routes = audio_paths, 316 .num_dapm_routes = ARRAY_SIZE(audio_paths), 317 318 .late_probe = littlemill_late_probe, 319 }; 320 321 static int littlemill_probe(struct platform_device *pdev) 322 { 323 struct snd_soc_card *card = &littlemill; 324 int ret; 325 326 card->dev = &pdev->dev; 327 328 ret = devm_snd_soc_register_card(&pdev->dev, card); 329 if (ret) 330 dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); 331 332 return ret; 333 } 334 335 static struct platform_driver littlemill_driver = { 336 .driver = { 337 .name = "littlemill", 338 .pm = &snd_soc_pm_ops, 339 }, 340 .probe = littlemill_probe, 341 }; 342 343 module_platform_driver(littlemill_driver); 344 345 MODULE_DESCRIPTION("Littlemill audio support"); 346 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 347 MODULE_LICENSE("GPL"); 348 MODULE_ALIAS("platform:littlemill"); 349