linux/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// mt8183-da7219-max98357.c
   4//      --  MT8183-DA7219-MAX98357 ALSA SoC machine driver
   5//
   6// Copyright (c) 2018 MediaTek Inc.
   7// Author: Shunli Wang <shunli.wang@mediatek.com>
   8
   9#include <linux/module.h>
  10#include <sound/pcm_params.h>
  11#include <sound/soc.h>
  12#include <sound/jack.h>
  13#include <linux/pinctrl/consumer.h>
  14
  15#include "mt8183-afe-common.h"
  16#include "../../codecs/da7219-aad.h"
  17#include "../../codecs/da7219.h"
  18
  19static struct snd_soc_jack headset_jack;
  20
  21/* Headset jack detection DAPM pins */
  22static struct snd_soc_jack_pin headset_jack_pins[] = {
  23        {
  24                .pin = "Headphone",
  25                .mask = SND_JACK_HEADPHONE,
  26        },
  27        {
  28                .pin = "Headset Mic",
  29                .mask = SND_JACK_MICROPHONE,
  30        },
  31};
  32
  33static struct snd_soc_dai_link_component
  34mt8183_da7219_max98357_external_codecs[] = {
  35        {
  36                .name = "max98357a",
  37                .dai_name = "HiFi",
  38        },
  39        {
  40                .name = "da7219.5-001a",
  41                .dai_name = "da7219-hifi",
  42        },
  43};
  44
  45static int mt8183_mt6358_i2s_hw_params(struct snd_pcm_substream *substream,
  46                                       struct snd_pcm_hw_params *params)
  47{
  48        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  49        unsigned int rate = params_rate(params);
  50        unsigned int mclk_fs_ratio = 128;
  51        unsigned int mclk_fs = rate * mclk_fs_ratio;
  52
  53        return snd_soc_dai_set_sysclk(rtd->cpu_dai,
  54                                      0, mclk_fs, SND_SOC_CLOCK_OUT);
  55}
  56
  57static const struct snd_soc_ops mt8183_mt6358_i2s_ops = {
  58        .hw_params = mt8183_mt6358_i2s_hw_params,
  59};
  60
  61static int mt8183_da7219_i2s_hw_params(struct snd_pcm_substream *substream,
  62                                       struct snd_pcm_hw_params *params)
  63{
  64        struct snd_soc_pcm_runtime *rtd = substream->private_data;
  65        unsigned int rate = params_rate(params);
  66        unsigned int mclk_fs_ratio = 256;
  67        unsigned int mclk_fs = rate * mclk_fs_ratio;
  68        unsigned int freq;
  69        int ret = 0, j;
  70
  71        ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0,
  72                                     mclk_fs, SND_SOC_CLOCK_OUT);
  73        if (ret < 0)
  74                dev_err(rtd->dev, "failed to set cpu dai sysclk\n");
  75
  76        for (j = 0; j < rtd->num_codecs; j++) {
  77                struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
  78
  79                if (!strcmp(codec_dai->component->name, "da7219.5-001a")) {
  80                        ret = snd_soc_dai_set_sysclk(codec_dai,
  81                                                     DA7219_CLKSRC_MCLK,
  82                                                     mclk_fs,
  83                                                     SND_SOC_CLOCK_IN);
  84                        if (ret < 0)
  85                                dev_err(rtd->dev, "failed to set sysclk\n");
  86
  87                        if ((rate % 8000) == 0)
  88                                freq = DA7219_PLL_FREQ_OUT_98304;
  89                        else
  90                                freq = DA7219_PLL_FREQ_OUT_90316;
  91
  92                        ret = snd_soc_dai_set_pll(codec_dai, 0,
  93                                                  DA7219_SYSCLK_PLL_SRM,
  94                                                  0, freq);
  95                        if (ret)
  96                                dev_err(rtd->dev, "failed to start PLL: %d\n",
  97                                        ret);
  98                }
  99        }
 100
 101        return ret;
 102}
 103
 104static int mt8183_da7219_hw_free(struct snd_pcm_substream *substream)
 105{
 106        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 107        int ret = 0, j;
 108
 109        for (j = 0; j < rtd->num_codecs; j++) {
 110                struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
 111
 112                if (!strcmp(codec_dai->component->name, "da7219.5-001a")) {
 113                        ret = snd_soc_dai_set_pll(codec_dai,
 114                                                  0, DA7219_SYSCLK_MCLK, 0, 0);
 115                        if (ret < 0) {
 116                                dev_err(rtd->dev, "failed to stop PLL: %d\n",
 117                                        ret);
 118                                break;
 119                        }
 120                }
 121        }
 122
 123        return ret;
 124}
 125
 126static const struct snd_soc_ops mt8183_da7219_i2s_ops = {
 127        .hw_params = mt8183_da7219_i2s_hw_params,
 128        .hw_free = mt8183_da7219_hw_free,
 129};
 130
 131static int mt8183_i2s_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 132                                      struct snd_pcm_hw_params *params)
 133{
 134        /* fix BE i2s format to 32bit, clean param mask first */
 135        snd_mask_reset_range(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT),
 136                             0, SNDRV_PCM_FORMAT_LAST);
 137
 138        params_set_format(params, SNDRV_PCM_FORMAT_S32_LE);
 139
 140        return 0;
 141}
 142
 143static const struct snd_soc_dapm_widget
 144mt8183_da7219_max98357_dapm_widgets[] = {
 145        SND_SOC_DAPM_OUTPUT("IT6505_8CH"),
 146};
 147
 148static const struct snd_soc_dapm_route mt8183_da7219_max98357_dapm_routes[] = {
 149        {"IT6505_8CH", NULL, "TDM"},
 150};
 151
 152static struct snd_soc_dai_link mt8183_da7219_max98357_dai_links[] = {
 153        /* FE */
 154        {
 155                .name = "Playback_1",
 156                .stream_name = "Playback_1",
 157                .cpu_dai_name = "DL1",
 158                .codec_name = "snd-soc-dummy",
 159                .codec_dai_name = "snd-soc-dummy-dai",
 160                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
 161                            SND_SOC_DPCM_TRIGGER_PRE},
 162                .dynamic = 1,
 163                .dpcm_playback = 1,
 164        },
 165        {
 166                .name = "Playback_2",
 167                .stream_name = "Playback_2",
 168                .cpu_dai_name = "DL2",
 169                .codec_name = "snd-soc-dummy",
 170                .codec_dai_name = "snd-soc-dummy-dai",
 171                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
 172                            SND_SOC_DPCM_TRIGGER_PRE},
 173                .dynamic = 1,
 174                .dpcm_playback = 1,
 175        },
 176        {
 177                .name = "Playback_3",
 178                .stream_name = "Playback_3",
 179                .cpu_dai_name = "DL3",
 180                .codec_name = "snd-soc-dummy",
 181                .codec_dai_name = "snd-soc-dummy-dai",
 182                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
 183                            SND_SOC_DPCM_TRIGGER_PRE},
 184                .dynamic = 1,
 185                .dpcm_playback = 1,
 186        },
 187        {
 188                .name = "Capture_1",
 189                .stream_name = "Capture_1",
 190                .cpu_dai_name = "UL1",
 191                .codec_name = "snd-soc-dummy",
 192                .codec_dai_name = "snd-soc-dummy-dai",
 193                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
 194                            SND_SOC_DPCM_TRIGGER_PRE},
 195                .dynamic = 1,
 196                .dpcm_capture = 1,
 197        },
 198        {
 199                .name = "Capture_2",
 200                .stream_name = "Capture_2",
 201                .cpu_dai_name = "UL2",
 202                .codec_name = "snd-soc-dummy",
 203                .codec_dai_name = "snd-soc-dummy-dai",
 204                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
 205                            SND_SOC_DPCM_TRIGGER_PRE},
 206                .dynamic = 1,
 207                .dpcm_capture = 1,
 208        },
 209        {
 210                .name = "Capture_3",
 211                .stream_name = "Capture_3",
 212                .cpu_dai_name = "UL3",
 213                .codec_name = "snd-soc-dummy",
 214                .codec_dai_name = "snd-soc-dummy-dai",
 215                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
 216                            SND_SOC_DPCM_TRIGGER_PRE},
 217                .dynamic = 1,
 218                .dpcm_capture = 1,
 219        },
 220        {
 221                .name = "Capture_Mono_1",
 222                .stream_name = "Capture_Mono_1",
 223                .cpu_dai_name = "UL_MONO_1",
 224                .codec_name = "snd-soc-dummy",
 225                .codec_dai_name = "snd-soc-dummy-dai",
 226                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
 227                            SND_SOC_DPCM_TRIGGER_PRE},
 228                .dynamic = 1,
 229                .dpcm_capture = 1,
 230        },
 231        {
 232                .name = "Playback_HDMI",
 233                .stream_name = "Playback_HDMI",
 234                .cpu_dai_name = "HDMI",
 235                .codec_name = "snd-soc-dummy",
 236                .codec_dai_name = "snd-soc-dummy-dai",
 237                .trigger = {SND_SOC_DPCM_TRIGGER_PRE,
 238                            SND_SOC_DPCM_TRIGGER_PRE},
 239                .dynamic = 1,
 240                .dpcm_playback = 1,
 241        },
 242        /* BE */
 243        {
 244                .name = "Primary Codec",
 245                .cpu_dai_name = "ADDA",
 246                .codec_dai_name = "mt6358-snd-codec-aif1",
 247                .codec_name = "mt6358-sound",
 248                .no_pcm = 1,
 249                .dpcm_playback = 1,
 250                .dpcm_capture = 1,
 251                .ignore_suspend = 1,
 252        },
 253        {
 254                .name = "PCM 1",
 255                .cpu_dai_name = "PCM 1",
 256                .codec_name = "snd-soc-dummy",
 257                .codec_dai_name = "snd-soc-dummy-dai",
 258                .no_pcm = 1,
 259                .dpcm_playback = 1,
 260                .dpcm_capture = 1,
 261                .ignore_suspend = 1,
 262        },
 263        {
 264                .name = "PCM 2",
 265                .cpu_dai_name = "PCM 2",
 266                .codec_name = "snd-soc-dummy",
 267                .codec_dai_name = "snd-soc-dummy-dai",
 268                .no_pcm = 1,
 269                .dpcm_playback = 1,
 270                .dpcm_capture = 1,
 271                .ignore_suspend = 1,
 272        },
 273        {
 274                .name = "I2S0",
 275                .cpu_dai_name = "I2S0",
 276                .codec_dai_name = "bt-sco-pcm",
 277                .codec_name = "bt-sco",
 278                .no_pcm = 1,
 279                .dpcm_capture = 1,
 280                .ignore_suspend = 1,
 281                .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
 282                .ops = &mt8183_mt6358_i2s_ops,
 283        },
 284        {
 285                .name = "I2S1",
 286                .cpu_dai_name = "I2S1",
 287                .codec_dai_name = "snd-soc-dummy-dai",
 288                .codec_name = "snd-soc-dummy",
 289                .no_pcm = 1,
 290                .dpcm_playback = 1,
 291                .ignore_suspend = 1,
 292                .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
 293                .ops = &mt8183_mt6358_i2s_ops,
 294        },
 295        {
 296                .name = "I2S2",
 297                .cpu_dai_name = "I2S2",
 298                .codec_dai_name = "da7219-hifi",
 299                .codec_name = "da7219.5-001a",
 300                .no_pcm = 1,
 301                .dpcm_capture = 1,
 302                .ignore_suspend = 1,
 303                .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
 304                .ops = &mt8183_da7219_i2s_ops,
 305        },
 306        {
 307                .name = "I2S3",
 308                .cpu_dai_name = "I2S3",
 309                .codecs = mt8183_da7219_max98357_external_codecs,
 310                .num_codecs =
 311                        ARRAY_SIZE(mt8183_da7219_max98357_external_codecs),
 312                .no_pcm = 1,
 313                .dpcm_playback = 1,
 314                .ignore_suspend = 1,
 315                .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
 316                .ops = &mt8183_da7219_i2s_ops,
 317        },
 318        {
 319                .name = "I2S5",
 320                .cpu_dai_name = "I2S5",
 321                .codec_dai_name = "bt-sco-pcm",
 322                .codec_name = "bt-sco",
 323                .no_pcm = 1,
 324                .dpcm_playback = 1,
 325                .ignore_suspend = 1,
 326                .be_hw_params_fixup = mt8183_i2s_hw_params_fixup,
 327                .ops = &mt8183_mt6358_i2s_ops,
 328        },
 329        {
 330                .name = "TDM",
 331                .cpu_dai_name = "TDM",
 332                .codec_name = "snd-soc-dummy",
 333                .codec_dai_name = "snd-soc-dummy-dai",
 334                .no_pcm = 1,
 335                .dpcm_playback = 1,
 336                .ignore_suspend = 1,
 337        },
 338};
 339
 340static int
 341mt8183_da7219_max98357_headset_init(struct snd_soc_component *component);
 342
 343static struct snd_soc_aux_dev mt8183_da7219_max98357_headset_dev = {
 344        .name = "Headset Chip",
 345        .init = mt8183_da7219_max98357_headset_init,
 346};
 347
 348static struct snd_soc_codec_conf mt6358_codec_conf[] = {
 349        {
 350                .dev_name = "mt6358-sound",
 351                .name_prefix = "Mt6358",
 352        },
 353};
 354
 355static struct snd_soc_card mt8183_da7219_max98357_card = {
 356        .name = "mt8183_da7219_max98357",
 357        .owner = THIS_MODULE,
 358        .dai_link = mt8183_da7219_max98357_dai_links,
 359        .num_links = ARRAY_SIZE(mt8183_da7219_max98357_dai_links),
 360        .aux_dev = &mt8183_da7219_max98357_headset_dev,
 361        .num_aux_devs = 1,
 362        .codec_conf = mt6358_codec_conf,
 363        .num_configs = ARRAY_SIZE(mt6358_codec_conf),
 364};
 365
 366static int
 367mt8183_da7219_max98357_headset_init(struct snd_soc_component *component)
 368{
 369        int ret;
 370
 371        /* Enable Headset and 4 Buttons Jack detection */
 372        ret = snd_soc_card_jack_new(&mt8183_da7219_max98357_card,
 373                                    "Headset Jack",
 374                                    SND_JACK_HEADSET |
 375                                    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 376                                    SND_JACK_BTN_2 | SND_JACK_BTN_3,
 377                                    &headset_jack,
 378                                    headset_jack_pins,
 379                                    ARRAY_SIZE(headset_jack_pins));
 380        if (ret)
 381                return ret;
 382
 383        da7219_aad_jack_det(component, &headset_jack);
 384
 385        return ret;
 386}
 387
 388static int mt8183_da7219_max98357_dev_probe(struct platform_device *pdev)
 389{
 390        struct snd_soc_card *card = &mt8183_da7219_max98357_card;
 391        struct device_node *platform_node;
 392        struct snd_soc_dai_link *dai_link;
 393        struct pinctrl *default_pins;
 394        int ret, i;
 395
 396        card->dev = &pdev->dev;
 397
 398        platform_node = of_parse_phandle(pdev->dev.of_node,
 399                                         "mediatek,platform", 0);
 400        if (!platform_node) {
 401                dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
 402                return -EINVAL;
 403        }
 404
 405        for_each_card_prelinks(card, i, dai_link) {
 406                /* In the alsa soc-core, the "platform" will be
 407                 * allocated by devm_kzalloc if null.
 408                 * There is a special case that registerring
 409                 * sound card is failed at the first time, but
 410                 * the "platform" will not null when probe is trying
 411                 * again. It's not expected normally.
 412                 */
 413                dai_link->platforms = NULL;
 414
 415                if (dai_link->platform_name)
 416                        continue;
 417                dai_link->platform_of_node = platform_node;
 418        }
 419
 420        mt8183_da7219_max98357_headset_dev.codec_of_node =
 421                of_parse_phandle(pdev->dev.of_node,
 422                                 "mediatek,headset-codec", 0);
 423        if (!mt8183_da7219_max98357_headset_dev.codec_of_node) {
 424                dev_err(&pdev->dev,
 425                        "Property 'mediatek,headset-codec' missing/invalid\n");
 426                return -EINVAL;
 427        }
 428
 429        ret = devm_snd_soc_register_card(&pdev->dev, card);
 430        if (ret) {
 431                dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
 432                        __func__, ret);
 433                return ret;
 434        }
 435
 436        default_pins =
 437                devm_pinctrl_get_select(&pdev->dev, PINCTRL_STATE_DEFAULT);
 438        if (IS_ERR(default_pins)) {
 439                dev_err(&pdev->dev, "%s set pins failed\n",
 440                        __func__);
 441                return PTR_ERR(default_pins);
 442        }
 443
 444        return ret;
 445}
 446
 447#ifdef CONFIG_OF
 448static const struct of_device_id mt8183_da7219_max98357_dt_match[] = {
 449        {.compatible = "mediatek,mt8183_da7219_max98357",},
 450        {}
 451};
 452#endif
 453
 454static struct platform_driver mt8183_da7219_max98357_driver = {
 455        .driver = {
 456                .name = "mt8183_da7219_max98357",
 457#ifdef CONFIG_OF
 458                .of_match_table = mt8183_da7219_max98357_dt_match,
 459#endif
 460        },
 461        .probe = mt8183_da7219_max98357_dev_probe,
 462};
 463
 464module_platform_driver(mt8183_da7219_max98357_driver);
 465
 466/* Module information */
 467MODULE_DESCRIPTION("MT8183-DA7219-MAX98357 ALSA SoC machine driver");
 468MODULE_AUTHOR("Shunli Wang <shunli.wang@mediatek.com>");
 469MODULE_LICENSE("GPL v2");
 470MODULE_ALIAS("mt8183_da7219_max98357 soc card");
 471
 472