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