midas_wm1811.c (13899B)
1// SPDX-License-Identifier: GPL-2.0+ 2// 3// Midas audio support 4// 5// Copyright (C) 2018 Simon Shields <simon@lineageos.org> 6// Copyright (C) 2020 Samsung Electronics Co., Ltd. 7 8#include <linux/clk.h> 9#include <linux/gpio/consumer.h> 10#include <linux/mfd/wm8994/registers.h> 11#include <linux/module.h> 12#include <linux/of.h> 13#include <linux/of_device.h> 14#include <linux/of_gpio.h> 15#include <linux/regulator/consumer.h> 16#include <sound/jack.h> 17#include <sound/soc.h> 18#include <sound/soc-dapm.h> 19 20#include "i2s.h" 21#include "../codecs/wm8994.h" 22 23/* 24 * The MCLK1 clock source is XCLKOUT with its mux set to the external fixed rate 25 * oscillator (XXTI). 26 */ 27#define MCLK1_RATE 24000000U 28#define MCLK2_RATE 32768U 29#define DEFAULT_FLL1_RATE 11289600U 30 31struct midas_priv { 32 struct regulator *reg_mic_bias; 33 struct regulator *reg_submic_bias; 34 struct gpio_desc *gpio_fm_sel; 35 struct gpio_desc *gpio_lineout_sel; 36 unsigned int fll1_rate; 37 38 struct snd_soc_jack headset_jack; 39}; 40 41static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate) 42{ 43 struct snd_soc_card *card = rtd->card; 44 struct midas_priv *priv = snd_soc_card_get_drvdata(card); 45 struct snd_soc_dai *aif1_dai = asoc_rtd_to_codec(rtd, 0); 46 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0); 47 int ret; 48 49 if (!rate) 50 rate = priv->fll1_rate; 51 /* 52 * If no new rate is requested, set FLL1 to a sane default for jack 53 * detection. 54 */ 55 if (!rate) 56 rate = DEFAULT_FLL1_RATE; 57 58 if (rate != priv->fll1_rate && priv->fll1_rate) { 59 /* while reconfiguring, switch to MCLK2 for SYSCLK */ 60 ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, 61 MCLK2_RATE, SND_SOC_CLOCK_IN); 62 if (ret < 0) { 63 dev_err(card->dev, "Unable to switch to MCLK2: %d\n", ret); 64 return ret; 65 } 66 } 67 68 ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, 69 MCLK1_RATE, rate); 70 if (ret < 0) { 71 dev_err(card->dev, "Failed to set FLL1 rate: %d\n", ret); 72 return ret; 73 } 74 priv->fll1_rate = rate; 75 76 ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_FLL1, 77 priv->fll1_rate, SND_SOC_CLOCK_IN); 78 if (ret < 0) { 79 dev_err(card->dev, "Failed to set SYSCLK source: %d\n", ret); 80 return ret; 81 } 82 83 ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_OPCLK, 0, 84 SAMSUNG_I2S_OPCLK_PCLK); 85 if (ret < 0) { 86 dev_err(card->dev, "Failed to set OPCLK source: %d\n", ret); 87 return ret; 88 } 89 90 return 0; 91} 92 93static int midas_stop_fll1(struct snd_soc_pcm_runtime *rtd) 94{ 95 struct snd_soc_card *card = rtd->card; 96 struct midas_priv *priv = snd_soc_card_get_drvdata(card); 97 struct snd_soc_dai *aif1_dai = asoc_rtd_to_codec(rtd, 0); 98 int ret; 99 100 ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, 101 MCLK2_RATE, SND_SOC_CLOCK_IN); 102 if (ret < 0) { 103 dev_err(card->dev, "Unable to switch to MCLK2: %d\n", ret); 104 return ret; 105 } 106 107 ret = snd_soc_dai_set_pll(aif1_dai, WM8994_FLL1, 0, 0, 0); 108 if (ret < 0) { 109 dev_err(card->dev, "Unable to stop FLL1: %d\n", ret); 110 return ret; 111 } 112 113 priv->fll1_rate = 0; 114 115 return 0; 116} 117 118static int midas_aif1_hw_params(struct snd_pcm_substream *substream, 119 struct snd_pcm_hw_params *params) 120{ 121 struct snd_soc_pcm_runtime *rtd = substream->private_data; 122 unsigned int pll_out; 123 124 /* AIF1CLK should be at least 3MHz for "optimal performance" */ 125 if (params_rate(params) == 8000 || params_rate(params) == 11025) 126 pll_out = params_rate(params) * 512; 127 else 128 pll_out = params_rate(params) * 256; 129 130 return midas_start_fll1(rtd, pll_out); 131} 132 133static const struct snd_soc_ops midas_aif1_ops = { 134 .hw_params = midas_aif1_hw_params, 135}; 136 137/* 138 * We only have a single external speaker, so mix stereo data 139 * to a single mono stream. 140 */ 141static int midas_ext_spkmode(struct snd_soc_dapm_widget *w, 142 struct snd_kcontrol *kcontrol, int event) 143{ 144 struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm); 145 int ret = 0; 146 147 switch (event) { 148 case SND_SOC_DAPM_PRE_PMU: 149 ret = snd_soc_component_update_bits(codec, WM8994_SPKOUT_MIXERS, 150 WM8994_SPKMIXR_TO_SPKOUTL_MASK, 151 WM8994_SPKMIXR_TO_SPKOUTL); 152 break; 153 case SND_SOC_DAPM_POST_PMD: 154 ret = snd_soc_component_update_bits(codec, WM8994_SPKOUT_MIXERS, 155 WM8994_SPKMIXR_TO_SPKOUTL_MASK, 156 0); 157 break; 158 } 159 160 return ret; 161} 162 163static int midas_mic_bias(struct snd_soc_dapm_widget *w, 164 struct snd_kcontrol *kcontrol, int event) 165{ 166 struct snd_soc_card *card = w->dapm->card; 167 struct midas_priv *priv = snd_soc_card_get_drvdata(card); 168 169 switch (event) { 170 case SND_SOC_DAPM_PRE_PMU: 171 return regulator_enable(priv->reg_mic_bias); 172 case SND_SOC_DAPM_POST_PMD: 173 return regulator_disable(priv->reg_mic_bias); 174 } 175 176 return 0; 177} 178 179static int midas_submic_bias(struct snd_soc_dapm_widget *w, 180 struct snd_kcontrol *kcontrol, int event) 181{ 182 struct snd_soc_card *card = w->dapm->card; 183 struct midas_priv *priv = snd_soc_card_get_drvdata(card); 184 185 switch (event) { 186 case SND_SOC_DAPM_PRE_PMU: 187 return regulator_enable(priv->reg_submic_bias); 188 case SND_SOC_DAPM_POST_PMD: 189 return regulator_disable(priv->reg_submic_bias); 190 } 191 192 return 0; 193} 194 195static int midas_fm_set(struct snd_soc_dapm_widget *w, 196 struct snd_kcontrol *kcontrol, int event) 197{ 198 struct snd_soc_card *card = w->dapm->card; 199 struct midas_priv *priv = snd_soc_card_get_drvdata(card); 200 201 if (!priv->gpio_fm_sel) 202 return 0; 203 204 switch (event) { 205 case SND_SOC_DAPM_PRE_PMU: 206 gpiod_set_value_cansleep(priv->gpio_fm_sel, 1); 207 break; 208 case SND_SOC_DAPM_POST_PMD: 209 gpiod_set_value_cansleep(priv->gpio_fm_sel, 0); 210 break; 211 } 212 213 return 0; 214} 215 216static int midas_line_set(struct snd_soc_dapm_widget *w, 217 struct snd_kcontrol *kcontrol, int event) 218{ 219 struct snd_soc_card *card = w->dapm->card; 220 struct midas_priv *priv = snd_soc_card_get_drvdata(card); 221 222 if (!priv->gpio_lineout_sel) 223 return 0; 224 225 switch (event) { 226 case SND_SOC_DAPM_PRE_PMU: 227 gpiod_set_value_cansleep(priv->gpio_lineout_sel, 1); 228 break; 229 case SND_SOC_DAPM_POST_PMD: 230 gpiod_set_value_cansleep(priv->gpio_lineout_sel, 0); 231 break; 232 } 233 234 return 0; 235} 236 237static const struct snd_kcontrol_new midas_controls[] = { 238 SOC_DAPM_PIN_SWITCH("HP"), 239 240 SOC_DAPM_PIN_SWITCH("SPK"), 241 SOC_DAPM_PIN_SWITCH("RCV"), 242 243 SOC_DAPM_PIN_SWITCH("LINE"), 244 SOC_DAPM_PIN_SWITCH("HDMI"), 245 246 SOC_DAPM_PIN_SWITCH("Main Mic"), 247 SOC_DAPM_PIN_SWITCH("Sub Mic"), 248 SOC_DAPM_PIN_SWITCH("Headset Mic"), 249 250 SOC_DAPM_PIN_SWITCH("FM In"), 251}; 252 253static const struct snd_soc_dapm_widget midas_dapm_widgets[] = { 254 SND_SOC_DAPM_HP("HP", NULL), 255 256 SND_SOC_DAPM_SPK("SPK", midas_ext_spkmode), 257 SND_SOC_DAPM_SPK("RCV", NULL), 258 259 /* FIXME: toggle MAX77693 on i9300/i9305 */ 260 SND_SOC_DAPM_LINE("LINE", midas_line_set), 261 SND_SOC_DAPM_LINE("HDMI", NULL), 262 SND_SOC_DAPM_LINE("FM In", midas_fm_set), 263 264 SND_SOC_DAPM_MIC("Headset Mic", NULL), 265 SND_SOC_DAPM_MIC("Main Mic", midas_mic_bias), 266 SND_SOC_DAPM_MIC("Sub Mic", midas_submic_bias), 267}; 268 269static int midas_set_bias_level(struct snd_soc_card *card, 270 struct snd_soc_dapm_context *dapm, 271 enum snd_soc_bias_level level) 272{ 273 struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card, 274 &card->dai_link[0]); 275 struct snd_soc_dai *aif1_dai = asoc_rtd_to_codec(rtd, 0); 276 277 if (dapm->dev != aif1_dai->dev) 278 return 0; 279 280 switch (level) { 281 case SND_SOC_BIAS_STANDBY: 282 return midas_stop_fll1(rtd); 283 case SND_SOC_BIAS_PREPARE: 284 return midas_start_fll1(rtd, 0); 285 default: 286 break; 287 } 288 289 return 0; 290} 291 292static int midas_late_probe(struct snd_soc_card *card) 293{ 294 struct snd_soc_pcm_runtime *rtd = snd_soc_get_pcm_runtime(card, 295 &card->dai_link[0]); 296 struct snd_soc_dai *aif1_dai = asoc_rtd_to_codec(rtd, 0); 297 struct midas_priv *priv = snd_soc_card_get_drvdata(card); 298 int ret; 299 300 /* Use MCLK2 as SYSCLK for boot */ 301 ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, MCLK2_RATE, 302 SND_SOC_CLOCK_IN); 303 if (ret < 0) { 304 dev_err(aif1_dai->dev, "Failed to switch to MCLK2: %d\n", ret); 305 return ret; 306 } 307 308 ret = snd_soc_card_jack_new(card, "Headset", 309 SND_JACK_HEADSET | SND_JACK_MECHANICAL | 310 SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | 311 SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5, 312 &priv->headset_jack); 313 if (ret) 314 return ret; 315 316 wm8958_mic_detect(aif1_dai->component, &priv->headset_jack, 317 NULL, NULL, NULL, NULL); 318 return 0; 319} 320 321static struct snd_soc_dai_driver midas_ext_dai[] = { 322 { 323 .name = "Voice call", 324 .playback = { 325 .channels_min = 1, 326 .channels_max = 2, 327 .rate_min = 8000, 328 .rate_max = 16000, 329 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), 330 .formats = SNDRV_PCM_FMTBIT_S16_LE, 331 }, 332 .capture = { 333 .channels_min = 1, 334 .channels_max = 2, 335 .rate_min = 8000, 336 .rate_max = 16000, 337 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), 338 .formats = SNDRV_PCM_FMTBIT_S16_LE, 339 }, 340 }, 341 { 342 .name = "Bluetooth", 343 .playback = { 344 .channels_min = 1, 345 .channels_max = 2, 346 .rate_min = 8000, 347 .rate_max = 16000, 348 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), 349 .formats = SNDRV_PCM_FMTBIT_S16_LE, 350 }, 351 .capture = { 352 .channels_min = 1, 353 .channels_max = 2, 354 .rate_min = 8000, 355 .rate_max = 16000, 356 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), 357 .formats = SNDRV_PCM_FMTBIT_S16_LE, 358 }, 359 }, 360}; 361 362static const struct snd_soc_component_driver midas_component = { 363 .name = "midas-audio", 364}; 365 366SND_SOC_DAILINK_DEFS(wm1811_hifi, 367 DAILINK_COMP_ARRAY(COMP_EMPTY()), 368 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")), 369 DAILINK_COMP_ARRAY(COMP_EMPTY())); 370 371SND_SOC_DAILINK_DEFS(wm1811_voice, 372 DAILINK_COMP_ARRAY(COMP_EMPTY()), 373 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif2")), 374 DAILINK_COMP_ARRAY(COMP_EMPTY())); 375 376SND_SOC_DAILINK_DEFS(wm1811_bt, 377 DAILINK_COMP_ARRAY(COMP_EMPTY()), 378 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif3")), 379 DAILINK_COMP_ARRAY(COMP_EMPTY())); 380 381static struct snd_soc_dai_link midas_dai[] = { 382 { 383 .name = "WM8994 AIF1", 384 .stream_name = "HiFi Primary", 385 .ops = &midas_aif1_ops, 386 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 387 SND_SOC_DAIFMT_CBM_CFM, 388 SND_SOC_DAILINK_REG(wm1811_hifi), 389 }, { 390 .name = "WM1811 Voice", 391 .stream_name = "Voice call", 392 .ignore_suspend = 1, 393 SND_SOC_DAILINK_REG(wm1811_voice), 394 }, { 395 .name = "WM1811 BT", 396 .stream_name = "Bluetooth", 397 .ignore_suspend = 1, 398 SND_SOC_DAILINK_REG(wm1811_bt), 399 }, 400}; 401 402static struct snd_soc_card midas_card = { 403 .name = "Midas WM1811", 404 .owner = THIS_MODULE, 405 406 .dai_link = midas_dai, 407 .num_links = ARRAY_SIZE(midas_dai), 408 .controls = midas_controls, 409 .num_controls = ARRAY_SIZE(midas_controls), 410 .dapm_widgets = midas_dapm_widgets, 411 .num_dapm_widgets = ARRAY_SIZE(midas_dapm_widgets), 412 413 .set_bias_level = midas_set_bias_level, 414 .late_probe = midas_late_probe, 415}; 416 417static int midas_probe(struct platform_device *pdev) 418{ 419 struct device_node *cpu_dai_node = NULL, *codec_dai_node = NULL; 420 struct device_node *cpu = NULL, *codec = NULL; 421 struct snd_soc_card *card = &midas_card; 422 struct device *dev = &pdev->dev; 423 static struct snd_soc_dai_link *dai_link; 424 struct midas_priv *priv; 425 int ret, i; 426 427 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 428 if (!priv) 429 return -ENOMEM; 430 431 snd_soc_card_set_drvdata(card, priv); 432 card->dev = dev; 433 434 priv->reg_mic_bias = devm_regulator_get(dev, "mic-bias"); 435 if (IS_ERR(priv->reg_mic_bias)) { 436 dev_err(dev, "Failed to get mic bias regulator\n"); 437 return PTR_ERR(priv->reg_mic_bias); 438 } 439 440 priv->reg_submic_bias = devm_regulator_get(dev, "submic-bias"); 441 if (IS_ERR(priv->reg_submic_bias)) { 442 dev_err(dev, "Failed to get submic bias regulator\n"); 443 return PTR_ERR(priv->reg_submic_bias); 444 } 445 446 priv->gpio_fm_sel = devm_gpiod_get_optional(dev, "fm-sel", GPIOD_OUT_HIGH); 447 if (IS_ERR(priv->gpio_fm_sel)) { 448 dev_err(dev, "Failed to get FM selection GPIO\n"); 449 return PTR_ERR(priv->gpio_fm_sel); 450 } 451 452 priv->gpio_lineout_sel = devm_gpiod_get_optional(dev, "lineout-sel", 453 GPIOD_OUT_HIGH); 454 if (IS_ERR(priv->gpio_lineout_sel)) { 455 dev_err(dev, "Failed to get line out selection GPIO\n"); 456 return PTR_ERR(priv->gpio_lineout_sel); 457 } 458 459 ret = snd_soc_of_parse_card_name(card, "model"); 460 if (ret < 0) { 461 dev_err(dev, "Card name is not specified\n"); 462 return ret; 463 } 464 465 ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); 466 if (ret < 0) { 467 dev_err(dev, "Audio routing invalid/unspecified\n"); 468 return ret; 469 } 470 471 cpu = of_get_child_by_name(dev->of_node, "cpu"); 472 if (!cpu) 473 return -EINVAL; 474 475 codec = of_get_child_by_name(dev->of_node, "codec"); 476 if (!codec) { 477 of_node_put(cpu); 478 return -EINVAL; 479 } 480 481 cpu_dai_node = of_parse_phandle(cpu, "sound-dai", 0); 482 of_node_put(cpu); 483 if (!cpu_dai_node) { 484 dev_err(dev, "parsing cpu/sound-dai failed\n"); 485 of_node_put(codec); 486 return -EINVAL; 487 } 488 489 codec_dai_node = of_parse_phandle(codec, "sound-dai", 0); 490 of_node_put(codec); 491 if (!codec_dai_node) { 492 dev_err(dev, "audio-codec property invalid/missing\n"); 493 ret = -EINVAL; 494 goto put_cpu_dai_node; 495 } 496 497 for_each_card_prelinks(card, i, dai_link) { 498 dai_link->codecs->of_node = codec_dai_node; 499 dai_link->cpus->of_node = cpu_dai_node; 500 dai_link->platforms->of_node = cpu_dai_node; 501 } 502 503 ret = devm_snd_soc_register_component(dev, &midas_component, 504 midas_ext_dai, ARRAY_SIZE(midas_ext_dai)); 505 if (ret < 0) { 506 dev_err(dev, "Failed to register component: %d\n", ret); 507 goto put_codec_dai_node; 508 } 509 510 ret = devm_snd_soc_register_card(dev, card); 511 if (ret < 0) { 512 dev_err(dev, "Failed to register card: %d\n", ret); 513 goto put_codec_dai_node; 514 } 515 516 return 0; 517 518put_codec_dai_node: 519 of_node_put(codec_dai_node); 520put_cpu_dai_node: 521 of_node_put(cpu_dai_node); 522 return ret; 523} 524 525static const struct of_device_id midas_of_match[] = { 526 { .compatible = "samsung,midas-audio" }, 527 { }, 528}; 529MODULE_DEVICE_TABLE(of, midas_of_match); 530 531static struct platform_driver midas_driver = { 532 .driver = { 533 .name = "midas-audio", 534 .of_match_table = midas_of_match, 535 .pm = &snd_soc_pm_ops, 536 }, 537 .probe = midas_probe, 538}; 539module_platform_driver(midas_driver); 540 541MODULE_AUTHOR("Simon Shields <simon@lineageos.org>"); 542MODULE_DESCRIPTION("ASoC support for Midas"); 543MODULE_LICENSE("GPL v2");