linux/sound/soc/intel/boards/bytcr_rt5640.c
<<
>>
Prefs
   1/*
   2 *  byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform
   3 *
   4 *  Copyright (C) 2014 Intel Corp
   5 *  Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
   6 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; version 2 of the License.
  11 *
  12 *  This program is distributed in the hope that it will be useful, but
  13 *  WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 *  General Public License for more details.
  16 *
  17 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  18 */
  19
  20#include <linux/init.h>
  21#include <linux/module.h>
  22#include <linux/platform_device.h>
  23#include <linux/acpi.h>
  24#include <linux/device.h>
  25#include <linux/dmi.h>
  26#include <linux/slab.h>
  27#include <asm/cpu_device_id.h>
  28#include <asm/platform_sst_audio.h>
  29#include <linux/clk.h>
  30#include <sound/pcm.h>
  31#include <sound/pcm_params.h>
  32#include <sound/soc.h>
  33#include <sound/jack.h>
  34#include "../../codecs/rt5640.h"
  35#include "../atom/sst-atom-controls.h"
  36#include "../common/sst-acpi.h"
  37#include "../common/sst-dsp.h"
  38
  39enum {
  40        BYT_RT5640_DMIC1_MAP,
  41        BYT_RT5640_DMIC2_MAP,
  42        BYT_RT5640_IN1_MAP,
  43        BYT_RT5640_IN3_MAP,
  44};
  45
  46#define BYT_RT5640_MAP(quirk)   ((quirk) & 0xff)
  47#define BYT_RT5640_DMIC_EN      BIT(16)
  48#define BYT_RT5640_MONO_SPEAKER BIT(17)
  49#define BYT_RT5640_DIFF_MIC     BIT(18) /* defaut is single-ended */
  50#define BYT_RT5640_SSP2_AIF2     BIT(19) /* default is using AIF1  */
  51#define BYT_RT5640_SSP0_AIF1     BIT(20)
  52#define BYT_RT5640_SSP0_AIF2     BIT(21)
  53#define BYT_RT5640_MCLK_EN      BIT(22)
  54#define BYT_RT5640_MCLK_25MHZ   BIT(23)
  55
  56struct byt_rt5640_private {
  57        struct clk *mclk;
  58};
  59
  60static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP |
  61                                        BYT_RT5640_DMIC_EN |
  62                                        BYT_RT5640_MCLK_EN;
  63
  64static void log_quirks(struct device *dev)
  65{
  66        if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC1_MAP)
  67                dev_info(dev, "quirk DMIC1_MAP enabled");
  68        if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_DMIC2_MAP)
  69                dev_info(dev, "quirk DMIC2_MAP enabled");
  70        if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN1_MAP)
  71                dev_info(dev, "quirk IN1_MAP enabled");
  72        if (BYT_RT5640_MAP(byt_rt5640_quirk) == BYT_RT5640_IN3_MAP)
  73                dev_info(dev, "quirk IN3_MAP enabled");
  74        if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN)
  75                dev_info(dev, "quirk DMIC enabled");
  76        if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER)
  77                dev_info(dev, "quirk MONO_SPEAKER enabled");
  78        if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC)
  79                dev_info(dev, "quirk DIFF_MIC enabled");
  80        if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2)
  81                dev_info(dev, "quirk SSP2_AIF2 enabled");
  82        if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1)
  83                dev_info(dev, "quirk SSP0_AIF1 enabled");
  84        if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)
  85                dev_info(dev, "quirk SSP0_AIF2 enabled");
  86        if (byt_rt5640_quirk & BYT_RT5640_MCLK_EN)
  87                dev_info(dev, "quirk MCLK_EN enabled");
  88        if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ)
  89                dev_info(dev, "quirk MCLK_25MHZ enabled");
  90}
  91
  92
  93#define BYT_CODEC_DAI1  "rt5640-aif1"
  94#define BYT_CODEC_DAI2  "rt5640-aif2"
  95
  96static inline struct snd_soc_dai *byt_get_codec_dai(struct snd_soc_card *card)
  97{
  98        struct snd_soc_pcm_runtime *rtd;
  99
 100        list_for_each_entry(rtd, &card->rtd_list, list) {
 101                if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI1,
 102                             strlen(BYT_CODEC_DAI1)))
 103                        return rtd->codec_dai;
 104                if (!strncmp(rtd->codec_dai->name, BYT_CODEC_DAI2,
 105                                strlen(BYT_CODEC_DAI2)))
 106                        return rtd->codec_dai;
 107
 108        }
 109        return NULL;
 110}
 111
 112static int platform_clock_control(struct snd_soc_dapm_widget *w,
 113                                  struct snd_kcontrol *k, int  event)
 114{
 115        struct snd_soc_dapm_context *dapm = w->dapm;
 116        struct snd_soc_card *card = dapm->card;
 117        struct snd_soc_dai *codec_dai;
 118        struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
 119        int ret;
 120
 121        codec_dai = byt_get_codec_dai(card);
 122        if (!codec_dai) {
 123                dev_err(card->dev,
 124                        "Codec dai not found; Unable to set platform clock\n");
 125                return -EIO;
 126        }
 127
 128        if (SND_SOC_DAPM_EVENT_ON(event)) {
 129                if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) {
 130                        ret = clk_prepare_enable(priv->mclk);
 131                        if (ret < 0) {
 132                                dev_err(card->dev,
 133                                        "could not configure MCLK state");
 134                                return ret;
 135                        }
 136                }
 137                ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
 138                                             48000 * 512,
 139                                             SND_SOC_CLOCK_IN);
 140        } else {
 141                /*
 142                 * Set codec clock source to internal clock before
 143                 * turning off the platform clock. Codec needs clock
 144                 * for Jack detection and button press
 145                 */
 146                ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK,
 147                                             0,
 148                                             SND_SOC_CLOCK_IN);
 149                if (!ret) {
 150                        if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk)
 151                                clk_disable_unprepare(priv->mclk);
 152                }
 153        }
 154
 155        if (ret < 0) {
 156                dev_err(card->dev, "can't set codec sysclk: %d\n", ret);
 157                return ret;
 158        }
 159
 160        return 0;
 161}
 162
 163static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = {
 164        SND_SOC_DAPM_HP("Headphone", NULL),
 165        SND_SOC_DAPM_MIC("Headset Mic", NULL),
 166        SND_SOC_DAPM_MIC("Internal Mic", NULL),
 167        SND_SOC_DAPM_SPK("Speaker", NULL),
 168        SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
 169                            platform_clock_control, SND_SOC_DAPM_PRE_PMU |
 170                            SND_SOC_DAPM_POST_PMD),
 171
 172};
 173
 174static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = {
 175        {"Headphone", NULL, "Platform Clock"},
 176        {"Headset Mic", NULL, "Platform Clock"},
 177        {"Internal Mic", NULL, "Platform Clock"},
 178        {"Speaker", NULL, "Platform Clock"},
 179
 180        {"Headset Mic", NULL, "MICBIAS1"},
 181        {"IN2P", NULL, "Headset Mic"},
 182        {"Headphone", NULL, "HPOL"},
 183        {"Headphone", NULL, "HPOR"},
 184};
 185
 186static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = {
 187        {"DMIC1", NULL, "Internal Mic"},
 188};
 189
 190static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = {
 191        {"DMIC2", NULL, "Internal Mic"},
 192};
 193
 194static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = {
 195        {"Internal Mic", NULL, "MICBIAS1"},
 196        {"IN1P", NULL, "Internal Mic"},
 197};
 198
 199static const struct snd_soc_dapm_route byt_rt5640_intmic_in3_map[] = {
 200        {"Internal Mic", NULL, "MICBIAS1"},
 201        {"IN3P", NULL, "Internal Mic"},
 202};
 203
 204static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif1_map[] = {
 205        {"ssp2 Tx", NULL, "codec_out0"},
 206        {"ssp2 Tx", NULL, "codec_out1"},
 207        {"codec_in0", NULL, "ssp2 Rx"},
 208        {"codec_in1", NULL, "ssp2 Rx"},
 209
 210        {"AIF1 Playback", NULL, "ssp2 Tx"},
 211        {"ssp2 Rx", NULL, "AIF1 Capture"},
 212};
 213
 214static const struct snd_soc_dapm_route byt_rt5640_ssp2_aif2_map[] = {
 215        {"ssp2 Tx", NULL, "codec_out0"},
 216        {"ssp2 Tx", NULL, "codec_out1"},
 217        {"codec_in0", NULL, "ssp2 Rx"},
 218        {"codec_in1", NULL, "ssp2 Rx"},
 219
 220        {"AIF2 Playback", NULL, "ssp2 Tx"},
 221        {"ssp2 Rx", NULL, "AIF2 Capture"},
 222};
 223
 224static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif1_map[] = {
 225        {"ssp0 Tx", NULL, "modem_out"},
 226        {"modem_in", NULL, "ssp0 Rx"},
 227
 228        {"AIF1 Playback", NULL, "ssp0 Tx"},
 229        {"ssp0 Rx", NULL, "AIF1 Capture"},
 230};
 231
 232static const struct snd_soc_dapm_route byt_rt5640_ssp0_aif2_map[] = {
 233        {"ssp0 Tx", NULL, "modem_out"},
 234        {"modem_in", NULL, "ssp0 Rx"},
 235
 236        {"AIF2 Playback", NULL, "ssp0 Tx"},
 237        {"ssp0 Rx", NULL, "AIF2 Capture"},
 238};
 239
 240static const struct snd_soc_dapm_route byt_rt5640_stereo_spk_map[] = {
 241        {"Speaker", NULL, "SPOLP"},
 242        {"Speaker", NULL, "SPOLN"},
 243        {"Speaker", NULL, "SPORP"},
 244        {"Speaker", NULL, "SPORN"},
 245};
 246
 247static const struct snd_soc_dapm_route byt_rt5640_mono_spk_map[] = {
 248        {"Speaker", NULL, "SPOLP"},
 249        {"Speaker", NULL, "SPOLN"},
 250};
 251
 252static const struct snd_kcontrol_new byt_rt5640_controls[] = {
 253        SOC_DAPM_PIN_SWITCH("Headphone"),
 254        SOC_DAPM_PIN_SWITCH("Headset Mic"),
 255        SOC_DAPM_PIN_SWITCH("Internal Mic"),
 256        SOC_DAPM_PIN_SWITCH("Speaker"),
 257};
 258
 259static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream,
 260                                        struct snd_pcm_hw_params *params)
 261{
 262        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 263        struct snd_soc_dai *codec_dai = rtd->codec_dai;
 264        int ret;
 265
 266        ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
 267                                     params_rate(params) * 512,
 268                                     SND_SOC_CLOCK_IN);
 269
 270        if (ret < 0) {
 271                dev_err(rtd->dev, "can't set codec clock %d\n", ret);
 272                return ret;
 273        }
 274
 275        if (!(byt_rt5640_quirk & BYT_RT5640_MCLK_EN)) {
 276                /* use bitclock as PLL input */
 277                if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
 278                        (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
 279
 280                        /* 2x16 bit slots on SSP0 */
 281                        ret = snd_soc_dai_set_pll(codec_dai, 0,
 282                                                RT5640_PLL1_S_BCLK1,
 283                                                params_rate(params) * 32,
 284                                                params_rate(params) * 512);
 285                } else {
 286                        /* 2x15 bit slots on SSP2 */
 287                        ret = snd_soc_dai_set_pll(codec_dai, 0,
 288                                                RT5640_PLL1_S_BCLK1,
 289                                                params_rate(params) * 50,
 290                                                params_rate(params) * 512);
 291                }
 292        } else {
 293                if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ) {
 294                        ret = snd_soc_dai_set_pll(codec_dai, 0,
 295                                                RT5640_PLL1_S_MCLK,
 296                                                25000000,
 297                                                params_rate(params) * 512);
 298                } else {
 299                        ret = snd_soc_dai_set_pll(codec_dai, 0,
 300                                                RT5640_PLL1_S_MCLK,
 301                                                19200000,
 302                                                params_rate(params) * 512);
 303                }
 304        }
 305
 306        if (ret < 0) {
 307                dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
 308                return ret;
 309        }
 310
 311        return 0;
 312}
 313
 314static int byt_rt5640_quirk_cb(const struct dmi_system_id *id)
 315{
 316        byt_rt5640_quirk = (unsigned long)id->driver_data;
 317        return 1;
 318}
 319
 320static const struct dmi_system_id byt_rt5640_quirk_table[] = {
 321        {
 322                .callback = byt_rt5640_quirk_cb,
 323                .matches = {
 324                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 325                        DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
 326                },
 327                .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
 328                                                 BYT_RT5640_MCLK_EN),
 329        },
 330        {
 331                .callback = byt_rt5640_quirk_cb,
 332                .matches = {
 333                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
 334                        DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"),
 335                },
 336                .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
 337                                                 BYT_RT5640_MONO_SPEAKER |
 338                                                 BYT_RT5640_DIFF_MIC |
 339                                                 BYT_RT5640_SSP0_AIF2 |
 340                                                 BYT_RT5640_MCLK_EN
 341                                                 ),
 342        },
 343        {
 344                .callback = byt_rt5640_quirk_cb,
 345                .matches = {
 346                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "DellInc."),
 347                        DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"),
 348                },
 349                .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP |
 350                                                 BYT_RT5640_DMIC_EN |
 351                                                 BYT_RT5640_MCLK_EN),
 352        },
 353        {
 354                .callback = byt_rt5640_quirk_cb,
 355                .matches = {
 356                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
 357                        DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"),
 358                },
 359                .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
 360                                                 BYT_RT5640_MCLK_EN),
 361        },
 362        {
 363                .callback = byt_rt5640_quirk_cb,
 364                .matches = {
 365                        DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"),
 366                        DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max B3 PLATFORM"),
 367                },
 368                .driver_data = (unsigned long *)(BYT_RT5640_DMIC1_MAP |
 369                                                 BYT_RT5640_DMIC_EN),
 370        },
 371        {
 372                .callback = byt_rt5640_quirk_cb,
 373                .matches = {
 374                        DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"),
 375                        DMI_MATCH(DMI_BOARD_NAME, "tPAD"),
 376                },
 377                .driver_data = (unsigned long *)(BYT_RT5640_IN3_MAP |
 378                                                BYT_RT5640_MCLK_EN |
 379                                                BYT_RT5640_SSP0_AIF1),
 380        },
 381        {
 382                .callback = byt_rt5640_quirk_cb,
 383                .matches = {
 384                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 385                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
 386                },
 387                .driver_data = (unsigned long *)(BYT_RT5640_IN1_MAP |
 388                                                 BYT_RT5640_MCLK_EN |
 389                                                 BYT_RT5640_SSP0_AIF1),
 390
 391        },
 392        {}
 393};
 394
 395static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime)
 396{
 397        int ret;
 398        struct snd_soc_codec *codec = runtime->codec;
 399        struct snd_soc_card *card = runtime->card;
 400        const struct snd_soc_dapm_route *custom_map;
 401        struct byt_rt5640_private *priv = snd_soc_card_get_drvdata(card);
 402        int num_routes;
 403
 404        card->dapm.idle_bias_off = true;
 405
 406        rt5640_sel_asrc_clk_src(codec,
 407                                RT5640_DA_STEREO_FILTER |
 408                                RT5640_DA_MONO_L_FILTER |
 409                                RT5640_DA_MONO_R_FILTER |
 410                                RT5640_AD_STEREO_FILTER |
 411                                RT5640_AD_MONO_L_FILTER |
 412                                RT5640_AD_MONO_R_FILTER,
 413                                RT5640_CLK_SEL_ASRC);
 414
 415        ret = snd_soc_add_card_controls(card, byt_rt5640_controls,
 416                                        ARRAY_SIZE(byt_rt5640_controls));
 417        if (ret) {
 418                dev_err(card->dev, "unable to add card controls\n");
 419                return ret;
 420        }
 421
 422        switch (BYT_RT5640_MAP(byt_rt5640_quirk)) {
 423        case BYT_RT5640_IN1_MAP:
 424                custom_map = byt_rt5640_intmic_in1_map;
 425                num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map);
 426                break;
 427        case BYT_RT5640_IN3_MAP:
 428                custom_map = byt_rt5640_intmic_in3_map;
 429                num_routes = ARRAY_SIZE(byt_rt5640_intmic_in3_map);
 430                break;
 431        case BYT_RT5640_DMIC2_MAP:
 432                custom_map = byt_rt5640_intmic_dmic2_map;
 433                num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map);
 434                break;
 435        default:
 436                custom_map = byt_rt5640_intmic_dmic1_map;
 437                num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map);
 438        }
 439
 440        ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes);
 441        if (ret)
 442                return ret;
 443
 444        if (byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) {
 445                ret = snd_soc_dapm_add_routes(&card->dapm,
 446                                        byt_rt5640_ssp2_aif2_map,
 447                                        ARRAY_SIZE(byt_rt5640_ssp2_aif2_map));
 448        } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) {
 449                ret = snd_soc_dapm_add_routes(&card->dapm,
 450                                        byt_rt5640_ssp0_aif1_map,
 451                                        ARRAY_SIZE(byt_rt5640_ssp0_aif1_map));
 452        } else if (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2) {
 453                ret = snd_soc_dapm_add_routes(&card->dapm,
 454                                        byt_rt5640_ssp0_aif2_map,
 455                                        ARRAY_SIZE(byt_rt5640_ssp0_aif2_map));
 456        } else {
 457                ret = snd_soc_dapm_add_routes(&card->dapm,
 458                                        byt_rt5640_ssp2_aif1_map,
 459                                        ARRAY_SIZE(byt_rt5640_ssp2_aif1_map));
 460        }
 461        if (ret)
 462                return ret;
 463
 464        if (byt_rt5640_quirk & BYT_RT5640_MONO_SPEAKER) {
 465                ret = snd_soc_dapm_add_routes(&card->dapm,
 466                                        byt_rt5640_mono_spk_map,
 467                                        ARRAY_SIZE(byt_rt5640_mono_spk_map));
 468        } else {
 469                ret = snd_soc_dapm_add_routes(&card->dapm,
 470                                        byt_rt5640_stereo_spk_map,
 471                                        ARRAY_SIZE(byt_rt5640_stereo_spk_map));
 472        }
 473        if (ret)
 474                return ret;
 475
 476        if (byt_rt5640_quirk & BYT_RT5640_DIFF_MIC) {
 477                snd_soc_update_bits(codec,  RT5640_IN1_IN2, RT5640_IN_DF1,
 478                                    RT5640_IN_DF1);
 479        }
 480
 481        if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) {
 482                ret = rt5640_dmic_enable(codec, 0, 0);
 483                if (ret)
 484                        return ret;
 485        }
 486
 487        snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone");
 488        snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker");
 489
 490        if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk) {
 491                /*
 492                 * The firmware might enable the clock at
 493                 * boot (this information may or may not
 494                 * be reflected in the enable clock register).
 495                 * To change the rate we must disable the clock
 496                 * first to cover these cases. Due to common
 497                 * clock framework restrictions that do not allow
 498                 * to disable a clock that has not been enabled,
 499                 * we need to enable the clock first.
 500                 */
 501                ret = clk_prepare_enable(priv->mclk);
 502                if (!ret)
 503                        clk_disable_unprepare(priv->mclk);
 504
 505                if (byt_rt5640_quirk & BYT_RT5640_MCLK_25MHZ)
 506                        ret = clk_set_rate(priv->mclk, 25000000);
 507                else
 508                        ret = clk_set_rate(priv->mclk, 19200000);
 509
 510                if (ret)
 511                        dev_err(card->dev, "unable to set MCLK rate\n");
 512        }
 513
 514        return ret;
 515}
 516
 517static const struct snd_soc_pcm_stream byt_rt5640_dai_params = {
 518        .formats = SNDRV_PCM_FMTBIT_S24_LE,
 519        .rate_min = 48000,
 520        .rate_max = 48000,
 521        .channels_min = 2,
 522        .channels_max = 2,
 523};
 524
 525static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd,
 526                            struct snd_pcm_hw_params *params)
 527{
 528        struct snd_interval *rate = hw_param_interval(params,
 529                        SNDRV_PCM_HW_PARAM_RATE);
 530        struct snd_interval *channels = hw_param_interval(params,
 531                                                SNDRV_PCM_HW_PARAM_CHANNELS);
 532        int ret;
 533
 534        /* The DSP will covert the FE rate to 48k, stereo */
 535        rate->min = rate->max = 48000;
 536        channels->min = channels->max = 2;
 537
 538        if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
 539                (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
 540
 541                /* set SSP0 to 16-bit */
 542                params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);
 543
 544                /*
 545                 * Default mode for SSP configuration is TDM 4 slot, override config
 546                 * with explicit setting to I2S 2ch 16-bit. The word length is set with
 547                 * dai_set_tdm_slot() since there is no other API exposed
 548                 */
 549                ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
 550                                        SND_SOC_DAIFMT_I2S     |
 551                                        SND_SOC_DAIFMT_NB_IF   |
 552                                        SND_SOC_DAIFMT_CBS_CFS
 553                        );
 554                if (ret < 0) {
 555                        dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
 556                        return ret;
 557                }
 558
 559                ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 16);
 560                if (ret < 0) {
 561                        dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
 562                        return ret;
 563                }
 564
 565        } else {
 566
 567                /* set SSP2 to 24-bit */
 568                params_set_format(params, SNDRV_PCM_FORMAT_S24_LE);
 569
 570                /*
 571                 * Default mode for SSP configuration is TDM 4 slot, override config
 572                 * with explicit setting to I2S 2ch 24-bit. The word length is set with
 573                 * dai_set_tdm_slot() since there is no other API exposed
 574                 */
 575                ret = snd_soc_dai_set_fmt(rtd->cpu_dai,
 576                                        SND_SOC_DAIFMT_I2S     |
 577                                        SND_SOC_DAIFMT_NB_IF   |
 578                                        SND_SOC_DAIFMT_CBS_CFS
 579                        );
 580                if (ret < 0) {
 581                        dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret);
 582                        return ret;
 583                }
 584
 585                ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24);
 586                if (ret < 0) {
 587                        dev_err(rtd->dev, "can't set I2S config, err %d\n", ret);
 588                        return ret;
 589                }
 590        }
 591        return 0;
 592}
 593
 594static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream)
 595{
 596        return snd_pcm_hw_constraint_single(substream->runtime,
 597                        SNDRV_PCM_HW_PARAM_RATE, 48000);
 598}
 599
 600static struct snd_soc_ops byt_rt5640_aif1_ops = {
 601        .startup = byt_rt5640_aif1_startup,
 602};
 603
 604static struct snd_soc_ops byt_rt5640_be_ssp2_ops = {
 605        .hw_params = byt_rt5640_aif1_hw_params,
 606};
 607
 608static struct snd_soc_dai_link byt_rt5640_dais[] = {
 609        [MERR_DPCM_AUDIO] = {
 610                .name = "Baytrail Audio Port",
 611                .stream_name = "Baytrail Audio",
 612                .cpu_dai_name = "media-cpu-dai",
 613                .codec_dai_name = "snd-soc-dummy-dai",
 614                .codec_name = "snd-soc-dummy",
 615                .platform_name = "sst-mfld-platform",
 616                .ignore_suspend = 1,
 617                .dynamic = 1,
 618                .dpcm_playback = 1,
 619                .dpcm_capture = 1,
 620                .ops = &byt_rt5640_aif1_ops,
 621        },
 622        [MERR_DPCM_DEEP_BUFFER] = {
 623                .name = "Deep-Buffer Audio Port",
 624                .stream_name = "Deep-Buffer Audio",
 625                .cpu_dai_name = "deepbuffer-cpu-dai",
 626                .codec_dai_name = "snd-soc-dummy-dai",
 627                .codec_name = "snd-soc-dummy",
 628                .platform_name = "sst-mfld-platform",
 629                .ignore_suspend = 1,
 630                .nonatomic = true,
 631                .dynamic = 1,
 632                .dpcm_playback = 1,
 633                .ops = &byt_rt5640_aif1_ops,
 634        },
 635        [MERR_DPCM_COMPR] = {
 636                .name = "Baytrail Compressed Port",
 637                .stream_name = "Baytrail Compress",
 638                .cpu_dai_name = "compress-cpu-dai",
 639                .codec_dai_name = "snd-soc-dummy-dai",
 640                .codec_name = "snd-soc-dummy",
 641                .platform_name = "sst-mfld-platform",
 642        },
 643                /* back ends */
 644        {
 645                .name = "SSP2-Codec",
 646                .id = 1,
 647                .cpu_dai_name = "ssp2-port", /* overwritten for ssp0 routing */
 648                .platform_name = "sst-mfld-platform",
 649                .no_pcm = 1,
 650                .codec_dai_name = "rt5640-aif1", /* changed w/ quirk */
 651                .codec_name = "i2c-10EC5640:00", /* overwritten with HID */
 652                .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
 653                                                | SND_SOC_DAIFMT_CBS_CFS,
 654                .be_hw_params_fixup = byt_rt5640_codec_fixup,
 655                .ignore_suspend = 1,
 656                .dpcm_playback = 1,
 657                .dpcm_capture = 1,
 658                .init = byt_rt5640_init,
 659                .ops = &byt_rt5640_be_ssp2_ops,
 660        },
 661};
 662
 663/* SoC card */
 664static struct snd_soc_card byt_rt5640_card = {
 665        .name = "bytcr-rt5640",
 666        .owner = THIS_MODULE,
 667        .dai_link = byt_rt5640_dais,
 668        .num_links = ARRAY_SIZE(byt_rt5640_dais),
 669        .dapm_widgets = byt_rt5640_widgets,
 670        .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets),
 671        .dapm_routes = byt_rt5640_audio_map,
 672        .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map),
 673        .fully_routed = true,
 674};
 675
 676static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */
 677static char byt_rt5640_codec_aif_name[12]; /*  = "rt5640-aif[1|2]" */
 678static char byt_rt5640_cpu_dai_name[10]; /*  = "ssp[0|2]-port" */
 679
 680static bool is_valleyview(void)
 681{
 682        static const struct x86_cpu_id cpu_ids[] = {
 683                { X86_VENDOR_INTEL, 6, 55 }, /* Valleyview, Bay Trail */
 684                {}
 685        };
 686
 687        if (!x86_match_cpu(cpu_ids))
 688                return false;
 689        return true;
 690}
 691
 692
 693static int snd_byt_rt5640_mc_probe(struct platform_device *pdev)
 694{
 695        int ret_val = 0;
 696        struct sst_acpi_mach *mach;
 697        const char *i2c_name = NULL;
 698        int i;
 699        int dai_index;
 700        struct byt_rt5640_private *priv;
 701
 702        priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC);
 703        if (!priv)
 704                return -ENOMEM;
 705
 706        /* register the soc card */
 707        byt_rt5640_card.dev = &pdev->dev;
 708        mach = byt_rt5640_card.dev->platform_data;
 709        snd_soc_card_set_drvdata(&byt_rt5640_card, priv);
 710
 711        /* fix index of codec dai */
 712        dai_index = MERR_DPCM_COMPR + 1;
 713        for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) {
 714                if (!strcmp(byt_rt5640_dais[i].codec_name, "i2c-10EC5640:00")) {
 715                        dai_index = i;
 716                        break;
 717                }
 718        }
 719
 720        /* fixup codec name based on HID */
 721        i2c_name = sst_acpi_find_name_from_hid(mach->id);
 722        if (i2c_name != NULL) {
 723                snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name),
 724                        "%s%s", "i2c-", i2c_name);
 725
 726                byt_rt5640_dais[dai_index].codec_name = byt_rt5640_codec_name;
 727        }
 728
 729        /*
 730         * swap SSP0 if bytcr is detected
 731         * (will be overridden if DMI quirk is detected)
 732         */
 733        if (is_valleyview()) {
 734                struct sst_platform_info *p_info = mach->pdata;
 735                const struct sst_res_info *res_info = p_info->res_info;
 736
 737                /* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */
 738                if (res_info->acpi_ipc_irq_index == 0) {
 739                        byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2;
 740                }
 741        }
 742
 743        /* check quirks before creating card */
 744        dmi_check_system(byt_rt5640_quirk_table);
 745        log_quirks(&pdev->dev);
 746
 747        if ((byt_rt5640_quirk & BYT_RT5640_SSP2_AIF2) ||
 748            (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
 749
 750                /* fixup codec aif name */
 751                snprintf(byt_rt5640_codec_aif_name,
 752                        sizeof(byt_rt5640_codec_aif_name),
 753                        "%s", "rt5640-aif2");
 754
 755                byt_rt5640_dais[dai_index].codec_dai_name =
 756                        byt_rt5640_codec_aif_name;
 757        }
 758
 759        if ((byt_rt5640_quirk & BYT_RT5640_SSP0_AIF1) ||
 760            (byt_rt5640_quirk & BYT_RT5640_SSP0_AIF2)) {
 761
 762                /* fixup cpu dai name name */
 763                snprintf(byt_rt5640_cpu_dai_name,
 764                        sizeof(byt_rt5640_cpu_dai_name),
 765                        "%s", "ssp0-port");
 766
 767                byt_rt5640_dais[dai_index].cpu_dai_name =
 768                        byt_rt5640_cpu_dai_name;
 769        }
 770
 771        if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && (is_valleyview())) {
 772                priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
 773                if (IS_ERR(priv->mclk)) {
 774                        dev_err(&pdev->dev,
 775                                "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
 776                                PTR_ERR(priv->mclk));
 777                        return PTR_ERR(priv->mclk);
 778                }
 779        }
 780
 781        ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card);
 782
 783        if (ret_val) {
 784                dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n",
 785                        ret_val);
 786                return ret_val;
 787        }
 788        platform_set_drvdata(pdev, &byt_rt5640_card);
 789        return ret_val;
 790}
 791
 792static struct platform_driver snd_byt_rt5640_mc_driver = {
 793        .driver = {
 794                .name = "bytcr_rt5640",
 795                .pm = &snd_soc_pm_ops,
 796        },
 797        .probe = snd_byt_rt5640_mc_probe,
 798};
 799
 800module_platform_driver(snd_byt_rt5640_mc_driver);
 801
 802MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
 803MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
 804MODULE_LICENSE("GPL v2");
 805MODULE_ALIAS("platform:bytcr_rt5640");
 806