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].name); 26 aif1_dai = rtd->codec_dai; 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].name); 73 aif1_dai = rtd->codec_dai; 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 = substream->private_data; 108 struct snd_soc_dai *codec_dai = rtd->codec_dai; 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 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 static struct snd_soc_dai_link littlemill_dai[] = { 146 { 147 .name = "CPU", 148 .stream_name = "CPU", 149 .cpu_dai_name = "samsung-i2s.0", 150 .codec_dai_name = "wm8994-aif1", 151 .platform_name = "samsung-i2s.0", 152 .codec_name = "wm8994-codec", 153 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 154 | SND_SOC_DAIFMT_CBM_CFM, 155 .ops = &littlemill_ops, 156 }, 157 { 158 .name = "Baseband", 159 .stream_name = "Baseband", 160 .cpu_dai_name = "wm8994-aif2", 161 .codec_dai_name = "wm1250-ev1", 162 .codec_name = "wm1250-ev1.1-0027", 163 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 164 | SND_SOC_DAIFMT_CBM_CFM, 165 .ignore_suspend = 1, 166 .params = &baseband_params, 167 }, 168 }; 169 170 static int bbclk_ev(struct snd_soc_dapm_widget *w, 171 struct snd_kcontrol *kcontrol, int event) 172 { 173 struct snd_soc_card *card = w->dapm->card; 174 struct snd_soc_pcm_runtime *rtd; 175 struct snd_soc_dai *aif2_dai; 176 int ret; 177 178 rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); 179 aif2_dai = rtd->cpu_dai; 180 181 switch (event) { 182 case SND_SOC_DAPM_PRE_PMU: 183 ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2, 184 WM8994_FLL_SRC_BCLK, 64 * 8000, 185 8000 * 256); 186 if (ret < 0) { 187 pr_err("Failed to start FLL: %d\n", ret); 188 return ret; 189 } 190 191 ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_FLL2, 192 8000 * 256, 193 SND_SOC_CLOCK_IN); 194 if (ret < 0) { 195 pr_err("Failed to set SYSCLK: %d\n", ret); 196 return ret; 197 } 198 break; 199 case SND_SOC_DAPM_POST_PMD: 200 ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2, 201 32768, SND_SOC_CLOCK_IN); 202 if (ret < 0) { 203 pr_err("Failed to switch away from FLL2: %d\n", ret); 204 return ret; 205 } 206 207 ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2, 208 0, 0, 0); 209 if (ret < 0) { 210 pr_err("Failed to stop FLL2: %d\n", ret); 211 return ret; 212 } 213 break; 214 default: 215 return -EINVAL; 216 } 217 218 return 0; 219 } 220 221 static const struct snd_kcontrol_new controls[] = { 222 SOC_DAPM_PIN_SWITCH("WM1250 Input"), 223 SOC_DAPM_PIN_SWITCH("WM1250 Output"), 224 }; 225 226 static struct snd_soc_dapm_widget widgets[] = { 227 SND_SOC_DAPM_HP("Headphone", NULL), 228 229 SND_SOC_DAPM_MIC("AMIC", NULL), 230 SND_SOC_DAPM_MIC("DMIC", NULL), 231 232 SND_SOC_DAPM_SUPPLY_S("Baseband Clock", -1, SND_SOC_NOPM, 0, 0, 233 bbclk_ev, 234 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), 235 }; 236 237 static struct snd_soc_dapm_route audio_paths[] = { 238 { "Headphone", NULL, "HPOUT1L" }, 239 { "Headphone", NULL, "HPOUT1R" }, 240 241 { "AMIC", NULL, "MICBIAS1" }, /* Default for AMICBIAS jumper */ 242 { "IN1LN", NULL, "AMIC" }, 243 244 { "DMIC", NULL, "MICBIAS2" }, /* Default for DMICBIAS jumper */ 245 { "DMIC1DAT", NULL, "DMIC" }, 246 { "DMIC2DAT", NULL, "DMIC" }, 247 248 { "AIF2CLK", NULL, "Baseband Clock" }, 249 }; 250 251 static struct snd_soc_jack littlemill_headset; 252 253 static int littlemill_late_probe(struct snd_soc_card *card) 254 { 255 struct snd_soc_pcm_runtime *rtd; 256 struct snd_soc_component *component; 257 struct snd_soc_dai *aif1_dai; 258 struct snd_soc_dai *aif2_dai; 259 int ret; 260 261 rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); 262 component = rtd->codec_dai->component; 263 aif1_dai = rtd->codec_dai; 264 265 rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); 266 aif2_dai = rtd->cpu_dai; 267 268 ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, 269 32768, SND_SOC_CLOCK_IN); 270 if (ret < 0) 271 return ret; 272 273 ret = snd_soc_dai_set_sysclk(aif2_dai, WM8994_SYSCLK_MCLK2, 274 32768, SND_SOC_CLOCK_IN); 275 if (ret < 0) 276 return ret; 277 278 ret = snd_soc_card_jack_new(card, "Headset", 279 SND_JACK_HEADSET | SND_JACK_MECHANICAL | 280 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 281 SND_JACK_BTN_2 | SND_JACK_BTN_3 | 282 SND_JACK_BTN_4 | SND_JACK_BTN_5, 283 &littlemill_headset, NULL, 0); 284 if (ret) 285 return ret; 286 287 /* This will check device compatibility itself */ 288 wm8958_mic_detect(component, &littlemill_headset, NULL, NULL, NULL, NULL); 289 290 /* As will this */ 291 wm8994_mic_detect(component, &littlemill_headset, 1); 292 293 return 0; 294 } 295 296 static struct snd_soc_card littlemill = { 297 .name = "Littlemill", 298 .owner = THIS_MODULE, 299 .dai_link = littlemill_dai, 300 .num_links = ARRAY_SIZE(littlemill_dai), 301 302 .set_bias_level = littlemill_set_bias_level, 303 .set_bias_level_post = littlemill_set_bias_level_post, 304 305 .controls = controls, 306 .num_controls = ARRAY_SIZE(controls), 307 .dapm_widgets = widgets, 308 .num_dapm_widgets = ARRAY_SIZE(widgets), 309 .dapm_routes = audio_paths, 310 .num_dapm_routes = ARRAY_SIZE(audio_paths), 311 312 .late_probe = littlemill_late_probe, 313 }; 314 315 static int littlemill_probe(struct platform_device *pdev) 316 { 317 struct snd_soc_card *card = &littlemill; 318 int ret; 319 320 card->dev = &pdev->dev; 321 322 ret = devm_snd_soc_register_card(&pdev->dev, card); 323 if (ret) 324 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", 325 ret); 326 327 return ret; 328 } 329 330 static struct platform_driver littlemill_driver = { 331 .driver = { 332 .name = "littlemill", 333 .pm = &snd_soc_pm_ops, 334 }, 335 .probe = littlemill_probe, 336 }; 337 338 module_platform_driver(littlemill_driver); 339 340 MODULE_DESCRIPTION("Littlemill audio support"); 341 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 342 MODULE_LICENSE("GPL"); 343 MODULE_ALIAS("platform:littlemill"); 344